Index: sys/kern/vfs_vnode.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_vnode.c,v retrieving revision 1.39 diff -p -u -4 -r1.39 vfs_vnode.c --- sys/kern/vfs_vnode.c 3 Oct 2014 14:45:38 -0000 1.39 +++ sys/kern/vfs_vnode.c 9 Mar 2015 09:35:05 -0000 @@ -1329,8 +1329,84 @@ again: return 0; } /* + * Create a new vnode / fs node pair and return it referenced through vpp. + */ +int +vcache_new(struct mount *mp, struct vnode *dvp, struct vattr *vap, + kauth_cred_t cred, struct vnode **vpp) +{ + int error; + uint32_t hash; + struct vnode *vp; + struct vcache_node *new_node; + struct vcache_node *old_node __diagused; + + *vpp = NULL; + + /* Allocate and initialize a new vcache / vnode pair. */ + error = vfs_busy(mp, NULL); + if (error) + return error; + new_node = pool_cache_get(vcache.pool, PR_WAITOK); + new_node->vn_key.vk_mount = mp; + new_node->vn_vnode = NULL; + vp = vnalloc(NULL); + + /* Create and load the fs node. */ + vp->v_iflag |= VI_CHANGING; + error = VFS_NEWVNODE(mp, dvp, vp, vap, cred, + &new_node->vn_key.vk_key_len, &new_node->vn_key.vk_key); + if (error) { + pool_cache_put(vcache.pool, new_node); + KASSERT(vp->v_usecount == 1); + vp->v_usecount = 0; + vnfree(vp); + vfs_unbusy(mp, false, NULL); + KASSERT(*vpp == NULL); + return error; + } + KASSERT(new_node->vn_key.vk_key != NULL); + KASSERT(vp->v_op != NULL); + hash = vcache_hash(&new_node->vn_key); + + /* Wait for previous instance to be reclaimed, then insert new node. */ + mutex_enter(&vcache.lock); + while ((old_node = vcache_hash_lookup(&new_node->vn_key, hash))) { +#ifdef DIAGNOSTIC + if (old_node->vn_vnode != NULL) + mutex_enter(old_node->vn_vnode->v_interlock); + KASSERT(old_node->vn_vnode == NULL || + (old_node->vn_vnode->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0); + if (old_node->vn_vnode != NULL) + mutex_exit(old_node->vn_vnode->v_interlock); +#endif + mutex_exit(&vcache.lock); + kpause("vcache", false, mstohz(20), NULL); + mutex_enter(&vcache.lock); + } + SLIST_INSERT_HEAD(&vcache.hashtab[hash & vcache.hashmask], + new_node, vn_hash); + mutex_exit(&vcache.lock); + vfs_insmntque(vp, mp); + if ((mp->mnt_iflag & IMNT_MPSAFE) != 0) + vp->v_vflag |= VV_MPSAFE; + vfs_unbusy(mp, true, NULL); + + /* Finished loading, finalize node. */ + mutex_enter(&vcache.lock); + new_node->vn_vnode = vp; + mutex_exit(&vcache.lock); + mutex_enter(vp->v_interlock); + vp->v_iflag &= ~VI_CHANGING; + cv_broadcast(&vp->v_cv); + mutex_exit(vp->v_interlock); + *vpp = vp; + return 0; +} + +/* * Prepare key change: lock old and new cache node. * Return an error if the new node already exists. */ int Index: sys/sys/mount.h =================================================================== RCS file: /cvsroot/src/sys/sys/mount.h,v retrieving revision 1.215 diff -p -u -4 -r1.215 mount.h --- sys/sys/mount.h 28 Jun 2014 22:27:50 -0000 1.215 +++ sys/sys/mount.h 9 Mar 2015 09:35:11 -0000 @@ -99,8 +99,9 @@ #ifndef _STANDALONE struct vnode; +struct vattr; /* * Structure per mounted file system. Each mounted file system has an * array of operations and an instance record. The file systems are @@ -221,8 +222,11 @@ struct vfsops { int (*vfs_sync) (struct mount *, int, struct kauth_cred *); int (*vfs_vget) (struct mount *, ino_t, struct vnode **); int (*vfs_loadvnode) (struct mount *, struct vnode *, const void *, size_t, const void **); + int (*vfs_newvnode) (struct mount *, struct vnode *, struct vnode *, + struct vattr *, kauth_cred_t, + size_t *, const void **); int (*vfs_fhtovp) (struct mount *, struct fid *, struct vnode **); int (*vfs_vptofh) (struct vnode *, struct fid *, size_t *); void (*vfs_init) (void); @@ -245,8 +249,10 @@ struct vfsops { /* XXX vget is actually file system internal. */ #define VFS_VGET(MP, INO, VPP) (*(MP)->mnt_op->vfs_vget)(MP, INO, VPP) #define VFS_LOADVNODE(MP, VP, KEY, KEY_LEN, NEW_KEY) \ (*(MP)->mnt_op->vfs_loadvnode)(MP, VP, KEY, KEY_LEN, NEW_KEY) +#define VFS_NEWVNODE(MP, DVP, VP, VAP, CRED, NEW_LEN, NEW_KEY) \ + (*(MP)->mnt_op->vfs_newvnode)(MP, DVP, VP, VAP, CRED, NEW_LEN, NEW_KEY) #define VFS_RENAMELOCK_ENTER(MP) (*(MP)->mnt_op->vfs_renamelock_enter)(MP) #define VFS_RENAMELOCK_EXIT(MP) (*(MP)->mnt_op->vfs_renamelock_exit)(MP) #define VFS_FSYNC(MP, VP, FLG) (*(MP)->mnt_op->vfs_fsync)(VP, FLG) @@ -286,8 +292,11 @@ int fsname##_statvfs(struct mount *, str int fsname##_sync(struct mount *, int, struct kauth_cred *); \ int fsname##_vget(struct mount *, ino_t, struct vnode **); \ int fsname##_loadvnode(struct mount *, struct vnode *, \ const void *, size_t, const void **); \ +int fsname##_newvnode(struct mount *, struct vnode *, \ + struct vnode *, struct vattr *, kauth_cred_t, \ + size_t *, const void **); \ int fsname##_fhtovp(struct mount *, struct fid *, struct vnode **); \ int fsname##_vptofh(struct vnode *, struct fid *, size_t *); \ void fsname##_init(void); \ void fsname##_reinit(void); \ Index: sys/sys/vnode.h =================================================================== RCS file: /cvsroot/src/sys/sys/vnode.h,v retrieving revision 1.249 diff -p -u -4 -r1.249 vnode.h --- sys/sys/vnode.h 5 Jul 2014 09:33:15 -0000 1.249 +++ sys/sys/vnode.h 9 Mar 2015 09:35:11 -0000 @@ -556,8 +556,10 @@ struct vnode * vnalloc(struct mount *); void vnfree(struct vnode *); void vremfree(struct vnode *); int vcache_get(struct mount *, const void *, size_t, struct vnode **); +int vcache_new(struct mount *, struct vnode *, + struct vattr *, kauth_cred_t, struct vnode **); int vcache_rekey_enter(struct mount *, struct vnode *, const void *, size_t, const void *, size_t); void vcache_rekey_exit(struct mount *, struct vnode *, const void *, size_t, const void *, size_t);