extern int vnode_fop_fsync( FILE_T *file_p, loff_t start, loff_t end, int datasync ) #endif { INODE_T *ip; int err; CALL_DATA_T cd; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) fsync_ctx ctx; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) if (file_p == NULL) { /* NFSD sometimes calls with null file_p and dentry_p filled in. */ ASSERT(dentry_p != NULL); ip = dentry_p->d_inode; } else #endif ip = file_p->f_dentry->d_inode; ASSERT_I_SEM_MINE(ip); ASSERT(MDKI_INOISOURS(ip)); if (!MDKI_INOISMVFS(ip)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) MDKI_VFS_LOG(VFS_LOG_ERR, "%s shouldn't be called? (files swapped " "at open): file_p=%p dp=%p\n", __func__, file_p, dentry_p); #else MDKI_VFS_LOG(VFS_LOG_ERR, "%s shouldn't be called? (files swapped " "at open): file_p=%p dp=%p\n", __func__, file_p, file_p->f_dentry); #endif return 0; /* don't fail the operation, though */ } mdki_linux_init_call_data(&cd); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) err = VOP_FSYNC(ITOV(ip), datasync == 0 ? FLAG_NODATASYNC : FLAG_DATASYNC, &cd, (file_ctx *)file_p); #else ctx.file_p = file_p; #if !defined (MRG) ctx.start = start; ctx.end = end; #endif /* !defined (MRG) */ err = VOP_FSYNC(ITOV(ip), datasync == 0 ? FLAG_NODATASYNC : FLAG_DATASYNC, &cd, &ctx); #endif /* else LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) */ err = mdki_errno_unix_to_linux(err); mdki_linux_destroy_call_data(&cd); return err; }
struct dentry * vnlayer_get_dentry( SUPER_T *sb, void *fhbits ) { int error; VFS_T *vfsp = SBTOVFS(sb); VNODE_T *vp; MDKI_FID_T *lfidp = fhbits; DENT_T *dp; CALL_DATA_T cd; mdki_linux_init_call_data(&cd); error = VFS_VGET(vfsp, &vp, lfidp, &cd); if (error == 0) { /* rebind if needed */ if (mfs_rebind_vpp(1, &vp, &cd)) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: vp %p rebound\n", __FUNCTION__, vp); } dp = vnlayer_find_dentry(vp); /* always drop vnode's refcount */ VN_RELE(vp); } else { dp = ERR_PTR(mdki_errno_unix_to_linux(error)); } mdki_linux_destroy_call_data(&cd); return dp; }
STATIC int vnlayer_unpack_fh( __u32 *fh, int len, /* counted in units of 4-bytes */ int fhtype, int fidlen, MDKI_FID_T *lfidp, MDKI_FID_T *plfidp ) { if (len * sizeof(*fh) < fhtype) { /* * we put the size in the type on the way out; * make sure we have enough data returning now */ MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: FH doesn't have enough data for type:" " has %d need %d\n", __func__, (int)(len * sizeof(*fh)), fhtype); return -EINVAL; } if ((fhtype & 1) != 0) { /* * The type/length must be even (there are two equal-sized * halves in the payload). Somebody might be fabricating file * handles? */ MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: FH type (%d) not even\n", __func__, fhtype); return -EINVAL; } if (lfidp != NULL) { /* object */ lfidp->fid_len = fidlen; BCOPY(fh, lfidp->fid_data, fidlen); } if (plfidp != NULL) { /* parent */ plfidp->fid_len = fidlen; BCOPY(((caddr_t)fh) + fidlen, plfidp->fid_data, fidlen); } return 0; }
struct dentry * vnlayer_decode_fh( SUPER_T *sb, __u32 *fh, int len, /* counted in units of 4-bytes */ int fhtype, int (*acceptable)(void *context, struct dentry *de), void *context ) { MDKI_FID_T *lfidp, *plfidp; DENT_T *dp; int error, fidlen; struct svc_export *exp = context; /* XXX cheating! */ SUPER_T *realsb = exp->ex_dentry->d_inode->i_sb; fidlen = fhtype >> 1; if (fidlen == 0) return ERR_PTR(-EINVAL); lfidp = KMEM_ALLOC(MDKI_FID_ALLOC_LEN(fidlen), KM_SLEEP); if (lfidp == NULL) return ERR_PTR(-ENOMEM); plfidp = KMEM_ALLOC(MDKI_FID_ALLOC_LEN(fidlen), KM_SLEEP); if (plfidp == NULL) { KMEM_FREE(lfidp, MDKI_FID_ALLOC_LEN(fidlen)); return ERR_PTR(-ENOMEM); } error = vnlayer_unpack_fh(fh, len, fhtype, fidlen, lfidp, plfidp); if (error == 0) { /* * We've extracted the identifying details from the * client-provided fid. Now use the system routines to handle * dentry tree work, it will call back to * sb->s_export_op->get_dentry to interpret either the parent * or the object. */ dp = (*realsb->s_export_op->find_exported_dentry)(realsb, lfidp, plfidp, acceptable, context); if (IS_ERR(dp)) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: pid %d call to find_exported_dentry returned error %ld\n", __FUNCTION__, current->pid, PTR_ERR(dp)); } } else { dp = ERR_PTR(error); } KMEM_FREE(lfidp, MDKI_FID_ALLOC_LEN(fidlen)); KMEM_FREE(plfidp, MDKI_FID_ALLOC_LEN(fidlen)); return dp; }
loff_t vnode_fop_llseek( FILE_T *file_p, loff_t offset, int origin ) { INODE_T *ip = file_p->f_dentry->d_inode; loff_t result; MOFFSET_T mresult; struct seek_ctx ctx; int err; ASSERT(MDKI_INOISMVFS(ip)); switch (origin) { case /* SEEK_SET */ 0: result = offset; break; case /* SEEK_CUR */ 1: result = offset + file_p->f_pos; break; case /* SEEK_END */ 2: result = offset + READ_I_SIZE(ip); break; default: #ifdef MVFS_DEBUG MDKI_VFS_LOG(VFS_LOG_INFO, "%s: invalid origin %d, ra=%p\n", __func__, origin, mdki_getmycaller()); #endif return -EINVAL; } ctx.filep = file_p; ctx.done = FALSE; ctx.offset = offset; ctx.origin = origin; mresult = result; err = VOP_SEEK(ITOV(ip), file_p->f_pos, &mresult, &ctx); err = mdki_errno_unix_to_linux(err); result = mresult; if (err) { ASSERT(err < 0); return err; } if (!ctx.done && result != file_p->f_pos) { file_p->f_pos = result; file_p->f_version = 0; /* See default_llseek() in fs/read_write.c */ } return result; }
int vnode_fop_open( INODE_T *ino_p, FILE_T *file_p ) { int status = 0; VNODE_T *avp; VNODE_T *vp; CALL_DATA_T cd; /* No asserts on BKL; locking protocol is changing */ ASSERT(MDKI_INOISOURS(ino_p)); if (!MDKI_INOISMVFS(ino_p)) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s shouldn't be called on shadow?" " (files swapped at open): vp %p fp %p\n", __func__, ino_p, file_p); return -ENOSYS; } if ((status = generic_file_open(ino_p, file_p))) { return status; } avp = ITOV(ino_p); vp = avp; mdki_linux_init_call_data(&cd); status = VOP_OPEN(&vp, vnlayer_filep_to_flags(file_p), &cd, (file_ctx *)file_p); status = mdki_errno_unix_to_linux(status); mdki_linux_destroy_call_data(&cd); MDKI_TRACE(TRACE_OPEN, "%s opened vp=%p fp=%p pvt=%p pcnt=%ld\n", __func__, vp, file_p, REALFILE(file_p), REALFILE(file_p) ? (long)F_COUNT(REALFILE(file_p)) : 0); if (avp != vp) { printk("switcheroo on open? %p became %p\n", avp, vp); /* XXX */ BUG(); } return status; }
extern int vnode_fop_flush( FILE_T *fp #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) || defined(SLES10SP2) , fl_owner_t id #endif ) { INODE_T *ip = fp->f_dentry->d_inode; int err; CALL_DATA_T cd; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) || defined(SLES10SP2) mdki_vop_close_ctx_t ctx; #endif ASSERT(MDKI_INOISOURS(ip)); if (!MDKI_INOISMVFS(ip)) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s shouldn't be called? (files swapped at open): fp %p\n", __func__, fp); return 0; /* don't fail the operation, though */ } mdki_linux_init_call_data(&cd); ASSERT(F_COUNT(fp) != VNODE_LASTCLOSE_COUNT); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) || defined(SLES10SP2) ctx.file_p = fp; ctx.owner_id = id; err = VOP_CLOSE(ITOV(ip), vnlayer_filep_to_flags(fp), F_COUNT(fp), (MOFFSET_T) 0, &cd, (file_ctx *)&ctx); #else err = VOP_CLOSE(ITOV(ip), vnlayer_filep_to_flags(fp), F_COUNT(fp), (MOFFSET_T) 0, &cd, (file_ctx *)fp); #endif err = mdki_errno_unix_to_linux(err); mdki_linux_destroy_call_data(&cd); return err; }
void mvfs_clear_inode(struct inode *inode_p) { CALL_DATA_T cd; ASSERT(MDKI_INOISOURS(inode_p)); if (MDKI_INOISMVFS(inode_p)) { /* If we're an mnode-base vnode, do all this stuff ... */ VNODE_T *vp = ITOV(inode_p); int error; ASSERT(I_COUNT(inode_p) == 0); ASSERT(inode_p->i_state & I_FREEING); mdki_linux_init_call_data(&cd); /* * Do actual deactivation of the vnode/mnode */ error = VOP_INACTIVE(vp, &cd); mdki_linux_destroy_call_data(&cd); if (error) MDKI_VFS_LOG(VFS_LOG_ERR, "mvfs_clear_inode: inactive error %d\n", error); } else if (MDKI_INOISCLRVN(inode_p)) { /* cleartext vnode */ vnlayer_linux_free_clrvnode(ITOV(inode_p)); } else { MDKI_TRACE(TRACE_INACTIVE,"no work: inode_p=%p vp=%p cnt=%d\n", inode_p, ITOV(inode_p), I_COUNT(inode_p)); } MDKI_TRACE(TRACE_INACTIVE,"inode_p=%p vp=%p cnt=%d\n", inode_p, ITOV(inode_p), I_COUNT(inode_p)); }
STATIC void vnode_iop_iattr2vattr( struct iattr *src, VATTR_T *dst ) { struct timespec curtime = CURRENT_TIME; VATTR_NULL(dst); if (src->ia_valid & ATTR_MODE) { VATTR_SET_TYPE(dst, vnlayer_mode_to_vtype(src->ia_mode)); VATTR_SET_MODE_RIGHTS(dst, src->ia_mode); dst->va_mask |= AT_MODE|AT_TYPE; } #define SET(UUU,lll) \ if (src->ia_valid & ATTR_ ## UUU) { \ VATTR_SET_ ## UUU(dst, src->ia_ ## lll); \ dst->va_mask |= AT_ ## UUU; \ } SET(UID,uid) SET(GID,gid) SET(SIZE,size) #undef SET if (src->ia_valid & ATTR_ATIME) { /* * If ATTR_ATIME is provided, but not ATTR_ATIME_SET, then we need * the current time. We have to pass ATTR_ATIME_SET through because * Linux uses it to control its validation. */ if (src->ia_valid & ATTR_ATIME_SET) { VATTR_SET_ATIME_TS(dst, &(src->ia_atime)); } else { VATTR_SET_ATIME_TS(dst, &curtime); } dst->va_mask |= AT_ATIME; } if (src->ia_valid & ATTR_ATIME_SET) dst->va_mask |= AT_ATIME_SET; if (src->ia_valid & ATTR_MTIME) { /* * If ATTR_MTIME is provided, but not ATTR_MTIME_SET, then we need * the current time. We have to pass ATTR_MTIME_SET through because * Linux uses it to control its validation. */ if (src->ia_valid & ATTR_MTIME_SET) { VATTR_SET_MTIME_TS(dst, &(src->ia_mtime)); } else { VATTR_SET_MTIME_TS(dst, &curtime); } dst->va_mask |= AT_MTIME; } if (src->ia_valid & ATTR_MTIME_SET) dst->va_mask |= AT_MTIME_SET; /* No current time hack needed for ctime. */ if (src->ia_valid & ATTR_CTIME) { VATTR_SET_CTIME_TS(dst, &(src->ia_ctime)); dst->va_mask |= AT_CTIME; } if (src->ia_valid & ATTR_ATTR_FLAG) { MDKI_VFS_LOG(VFS_LOG_ERR, "What to do with ATTR_FLAGs?: caller %p\n", mdki_getmycaller()); } return; }
/* * NFS access to vnode file systems. * * We provide dentry/inode_to_fh() and fh_to_dentry() methods so that the * vnode-based file system can hook up its VOP_FID() and VFS_VGET() * methods. The Linux NFS server calls these methods when encoding an * object into a file handle to be passed to the client for future * use, and when decoding a file handle and looking for the file * system object it describes. * * VOP_FID() takes a vnode and provides a file ID (fid) that can later * be presented (in a pair with a VFS pointer) to VFS_VGET() to * reconstitute that vnode. In a Sun ONC-NFS style kernel, VOP_FID() * is used twice per file handle, once for the exported directory and * once for the object itself. In Linux, the NFS layer itself handles * the export tree checking (depending on the status of * NFSEXP_NOSUBTREECHECK), so the file system only needs to fill in * the file handle with details for the object itself. We always * provide both object and parent in the file handle to be sure that * we don't end up short on file handle space in a future call that * requires both. * * On a call from the NFS client, the Linux NFS layer finds a * superblock pointer from the file handle passed by the NFS client, * then calls the fh_to_dentry() method to get a dentry. Sun ONC-NFS * kernels call VFS_VGET() on a vfsp, passing the FID portion of the * file handle. In this layer, we unpack the file handle, determine * whether the parent or the object is needed, and pass the info along * to a VFS_VGET() call. Once that returns, we look for an attached * dentry and use it, or fabricate a new one which NFS will attempt to * reconnect to the namespace. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) int vnlayer_inode_to_fh( struct inode *inode, __u32 *fh, int *lenp, struct inode *parent ) #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) */ int vnlayer_dentry_to_fh( struct dentry *dent, __u32 *fh, int *lenp, int need_parent ) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) */ { int error; int type; int mylen; MDKI_FID_T *lfidp = NULL; MDKI_FID_T *parent_fidp = NULL; mdki_boolean_t bailout_needed = TRUE; /* Assume we'll fail. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) SUPER_T *sbp; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) struct inode *inode = dent->d_inode; struct inode *parent = dent->d_parent->d_inode; #endif /* * We use the type byte (return value) to encode the FH length. Since we * always include two FIDs of the same size, the type must be even, so * that's how we "encode" the length of each FID (i.e. it is half the total * length). * * Always include parent entry; this makes sure that we only work with NFS * protocols that have enough room for our file handles. (Without this, we * may return a directory file handle OK yet be unable to return a plain * file handle.) Currently, we can just barely squeeze two standard * 10-byte vnode FIDs into the NFS v2 file handle. The NFS v3 handle has * plenty of room. */ ASSERT(ITOV(inode)); error = VOP_FID(ITOV(inode), &lfidp); if (error != 0) { ASSERT(lfidp == NULL); goto bailout; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) /* we may be called with a NULL parent */ if (parent == NULL) { /* in this case, fabricate a fake parent */ parent_fidp = (MDKI_FID_T *) KMEM_ALLOC(MDKI_FID_LEN(lfidp), KM_SLEEP); if (parent_fidp == NULL) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s: can't allocate %d bytes\n", __func__, (int) MDKI_FID_LEN(lfidp)); goto bailout; } memset(parent_fidp, 0xff, MDKI_FID_LEN(lfidp)); parent_fidp->fid_len = lfidp->fid_len; } else #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) */ { error = VOP_FID(ITOV(parent), &parent_fidp); if (error != 0) { ASSERT(parent_fidp == NULL); goto bailout; } } /* * Our encoding scheme can't tolerate different length FIDs * (because otherwise the type wouldn't be guaranteed to be even). */ if (parent_fidp->fid_len != lfidp->fid_len) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s: unbalanced parent/child fid lengths: %d, %d\n", __func__, parent_fidp->fid_len, lfidp->fid_len); goto bailout; } /* * vnode layer needs to release the storage for a fid on * Linux. The VOP_FID() function allocates its own fid in * non-error cases. Other UNIX systems release this storage * in the caller of VOP_FID, so we have to do it here. We * copy the vnode-style fid into the caller-allocated space, * then free our allocated version here. * * Remember: vnode lengths are counting bytes, Linux lengths count __u32 * units. */ type = parent_fidp->fid_len + lfidp->fid_len; /* Guaranteed even. */ mylen = roundup(type + MDKI_FID_EXTRA_SIZE, sizeof(*fh)); if (mylen == VNODE_NFS_FH_TYPE_RESERVED || mylen >= VNODE_NFS_FH_TYPE_ERROR) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: required length %d out of range (%d,%d)\n", __func__, mylen, VNODE_NFS_FH_TYPE_RESERVED, VNODE_NFS_FH_TYPE_ERROR); goto bailout; } if (((*lenp) * sizeof(*fh)) < mylen) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: need %d bytes for FH, have %d\n", __func__, mylen, (int) (sizeof(*fh) * (*lenp))); goto bailout; } /* Copy FIDs into file handle. */ *lenp = mylen / sizeof(*fh); /* No remainder because of roundup above. */ BZERO(fh, mylen); /* Zero whole fh to round up to __u32 boundary */ BCOPY(lfidp->fid_data, fh, lfidp->fid_len); BCOPY(parent_fidp->fid_data, ((caddr_t)fh) + (type / 2), parent_fidp->fid_len); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) /* * For 64 bits OS, use a 32 bits hash of the SB pointer. * For 32 bits OS, use the pointer itself. */ if (ITOV(inode) == NULL || ITOV(inode)->v_vfsmnt == NULL) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: %p is this a MVFS inode?\n", __func__, inode); goto bailout; } else { sbp = ((struct vfsmount *)ITOV(inode)->v_vfsmnt)->mnt_sb; } MDKI_FID_SET_SB_HASH(fh, type / 2, MDKI_FID_CALC_HASH(sbp)); #endif bailout_needed = FALSE; /* We're home free now. */ if (bailout_needed) { bailout: type = VNODE_NFS_FH_TYPE_ERROR; *lenp = 0; } #ifdef KMEMDEBUG if (lfidp != NULL) REAL_KMEM_FREE(lfidp, MDKI_FID_LEN(lfidp)); if (parent_fidp != NULL) REAL_KMEM_FREE(parent_fidp, MDKI_FID_LEN(parent_fidp)); #else if (lfidp != NULL) KMEM_FREE(lfidp, MDKI_FID_LEN(lfidp)); if (parent_fidp != NULL) KMEM_FREE(parent_fidp, MDKI_FID_LEN(parent_fidp)); #endif return type; }
int vnlayer_fill_super( SUPER_T *super_p, void *data_p, int silent ) { INODE_T *ino_p; VNODE_T *rootvp; VATTR_T va; VFS_T *vfsp; int err = 0; CALL_DATA_T cd; ASSERT_KERNEL_LOCKED(); /* sys_mount() */ ASSERT_SB_MOUNT_LOCKED_W(super_p); /* can't assert on mount_sem, we don't have access to it. */ if (vnlayer_vfs_opvec == NULL) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s: VFS operation not set yet " "(no file system module loaded?)\n", __func__); err = -ENODATA; goto return_NULL; } if (MDKI_INOISOURS(vnlayer_get_urdir_inode())) { /* can't handle this case */ MDKI_VFS_LOG(VFS_LOG_ERR, "%s: can't handle mounts inside setview.\n", __func__); err = -EINVAL; goto return_NULL; } /* * The only fields we have coming in are s_type and s_flags. */ /* Verify this */ super_p->s_blocksize = MVFS_DEF_BLKSIZE; super_p->s_blocksize_bits = MVFS_DEF_BLKSIZE_BITS; super_p->s_maxbytes = MVFS_DEF_MAX_FILESIZE; super_p->s_op = &mvfs_super_ops; super_p->s_export_op = &vnlayer_export_ops; super_p->dq_op = NULL; super_p->s_magic = MVFS_SUPER_MAGIC; /* * XXX This module is currently restricted to one client file system * type at a time, as registered via the vnlayer_vfs_opvec. */ vfsp = KMEM_ALLOC(sizeof(*vfsp), KM_SLEEP); if (vfsp == NULL) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s failed: no memory\n", __func__); SET_SBTOVFS(super_p, NULL); err = -ENOMEM; goto return_NULL; } BZERO(vfsp, sizeof(*vfsp)); SET_VFSTOSB(vfsp, super_p); SET_SBTOVFS(super_p, vfsp); vfsp->vfs_op = vnlayer_vfs_opvec; /* XXX fill in more of vfsp (flag?) */ if (super_p->s_flags & MS_RDONLY) vfsp->vfs_flag |= VFS_RDONLY; if (super_p->s_flags & MS_NOSUID) vfsp->vfs_flag |= VFS_NOSUID; err = vnlayer_linux_mount(vfsp, data_p); if (err) { goto bailout; } /* * Now create our dentry and set that up in the superblock. Get * the inode from the vnode at the root of the file system, and * attach it to a new dentry. */ mdki_linux_init_call_data(&cd); err = VFS_ROOT(SBTOVFS(super_p), &rootvp); if (err) { err = mdki_errno_unix_to_linux(err); (void) VFS_UNMOUNT(vfsp,&cd); mdki_linux_destroy_call_data(&cd); goto bailout; } ino_p = VTOI(rootvp); #ifdef CONFIG_FS_POSIX_ACL /* If the system supports ACLs, we set the flag in the superblock * depending on the ability of the underlying filesystem */ if (vfsp->vfs_flag & VFS_POSIXACL) { super_p->s_flags |= MS_POSIXACL; } #endif /* * Call getattr() to prime this inode with real attributes via the * callback to mdki_linux_vattr_pullup() */ VATTR_NULL(&va); /* ignore error code, we're committed */ (void) VOP_GETATTR(rootvp, &va, 0, &cd); /* This will allocate a dentry with a name of /, which is * what Linux uses in all filesystem roots. The dentry is * also not put on the hash chains because Linux does not * hash file system roots. It finds them through the super * blocks. */ super_p->s_root = VNODE_D_ALLOC_ROOT(ino_p); if (super_p->s_root) { if (VFSTOSB(vnlayer_looproot_vp->v_vfsp) == super_p) { /* loopback names are done with regular dentry ops */ MDKI_SET_DOPS(super_p->s_root, &vnode_dentry_ops); } else { /* * setview names come in via VOB mounts, they're marked * with setview dentry ops */ MDKI_SET_DOPS(super_p->s_root, &vnode_setview_dentry_ops); } super_p->s_root->d_fsdata = NULL; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) atomic_set(&super_p->s_root->d_count, 1); #endif /* d_alloc_root assumes that the caller will take care of * bumping the inode count for the dentry. So we will oblige */ igrab(ino_p); } else { VN_RELE(rootvp); (void) VFS_UNMOUNT(vfsp,&cd); mdki_linux_destroy_call_data(&cd); err = -ENOMEM; goto bailout; } mdki_linux_destroy_call_data(&cd); #if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) super_p->s_dirt = 1; /* we want to be called on write_super/sync() */ #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) /* write back is delegated to the undelying fs */ super_p->s_bdi = &noop_backing_dev_info; #endif /* * release reference on rootvp--super block holds appropriate * references now */ VN_RELE(rootvp); return(0); bailout: MDKI_VFS_LOG(VFS_LOG_ERR, "%s failed: error %d\n", __func__, vnlayer_errno_linux_to_unix(err)); SET_SBTOVFS(super_p, NULL); KMEM_FREE(vfsp, sizeof(*vfsp)); return_NULL: return(err); }
extern void mvfs_linux_umount_begin( struct vfsmount * mnt, int flags ) #endif { VNODE_T *vp; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \ LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) struct vfsmount *mnt; #else /* * Since 2.6.18 and before 2.6.27 we have mnt as a parameter. * But we still need super_p. */ SUPER_T *super_p = mnt->mnt_sb; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) int mount_count = 0; #endif ASSERT(super_p != NULL); ASSERT(super_p->s_root != NULL); vp = ITOV(super_p->s_root->d_inode); ASSERT(vp != NULL); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \ LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) mnt = VTOVFSMNT(vp); #else /* Check that the mountpoint passed in matches the one * from the vp that we are going to clear. Skip it otherwise. * We know from experience that this can happen when unmounting * loopback (bind) mounts. */ if (mnt != VTOVFSMNT(vp)) return; #endif /* Note that there is no mechanism for restoring the mount pointer * in the vnode if an error happens later on in the umount. This is * the only callback into the mvfs during umount. So far this has not * been a problem and if we don't do this here, the umount will never * succeed because the Linux code expects the mnt_count to be 2. * The count is 3 at this point from the initial allocation of the * vfsmnt structure, the path_lookup call in this umount call and * from when we placed the pointer in the vp. */ if (mnt == NULL) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s: mnt is NULL\n", __FUNCTION__); return; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) mount_count = MDKI_READ_MNT_COUNT(mnt); if (mount_count == 3) { MDKI_MNTPUT(mnt); SET_VTOVFSMNT(vp, NULL); } #else /* * may_umount returns !0 when the ref counter is 2 (and other conditions). * We took an extra ref, I'll drop it to test may_umount. If it is not * ready to be unmounted, the put is reverted. */ MDKI_MNTPUT(mnt); if (may_umount(mnt)) { SET_VTOVFSMNT(vp, NULL); } else { /* not ready yet */ MDKI_MNTGET(mnt); } #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) */ }
/* Common file handle decoding for both parent and dentry */ static struct dentry * vnlayer_decode_fh( SUPER_T *sb, struct fid *fh, int len, /* counted in units of 4-bytes */ int fhtype, int is_parent) { MDKI_FID_T *lfidp; DENT_T *dp; int error, fidlen; SUPER_T *realsb; unsigned realsb_hash; fidlen = fhtype >> 1; if (fidlen == 0) { return ERR_PTR(-EINVAL); } if (len * 4 < MDKI_FID_LEN_WITH_HASH(fidlen)) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: FH too small to be a MVFS FH\n", __FUNCTION__); return ERR_PTR(-EINVAL); } lfidp = KMEM_ALLOC(MDKI_FID_ALLOC_LEN(fidlen), KM_SLEEP); if (lfidp == NULL) { return ERR_PTR(-ENOMEM); } if (is_parent) { error = vnlayer_unpack_fh((__u32 *)fh, len, fhtype, fidlen, NULL, lfidp); } else { error = vnlayer_unpack_fh((__u32 *)fh, len, fhtype, fidlen, lfidp, NULL); } if (error == 0) { realsb_hash = MDKI_FID_SB_HASH(fh, fidlen); /* * Search in the VOB mount list for the super_block we encoded. * If the result is not NULL, the superblock was locked with * MDKI_LOCK_SB and must be unlocked with MDKI_UNLOCK_SB. */ realsb = (SUPER_T *) mvfs_find_mount(vnlayer_eval_mount, &realsb_hash); if (realsb != NULL) { /* * It found a matching VOB mount to this hash, we will leave to * vnlayer_get_dentry decides wether we can trust this FID, * it should be able to smell any staleness. */ dp = vnlayer_get_dentry(realsb, lfidp); MDKI_UNLOCK_SB(realsb); if (IS_ERR(dp)) { MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s: pid %d vnlayer_get_dentry returned error %ld\n", __FUNCTION__, current->pid, PTR_ERR(dp)); } } else { dp = ERR_PTR(-EINVAL); MDKI_VFS_LOG(VFS_LOG_ESTALE, "%s SB not found, hash=%08x\n", __FUNCTION__, realsb_hash); } } else { dp = ERR_PTR(error); } KMEM_FREE(lfidp, MDKI_FID_ALLOC_LEN(fidlen)); return dp; }
extern void mvfs_linux_umount_begin( struct vfsmount * mnt, int flags ) #endif { VNODE_T *vp; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \ LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) struct vfsmount *mnt; #else /* * Since 2.6.18 and before 2.6.27 we have mnt as a parameter. * But we still need super_p. */ SUPER_T *super_p = mnt->mnt_sb; #endif int mount_count = 0; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) && defined(CONFIG_SMP) int cpu; #endif ASSERT(super_p != NULL); ASSERT(super_p->s_root != NULL); vp = ITOV(super_p->s_root->d_inode); ASSERT(vp != NULL); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \ LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) mnt = VTOVFSMNT(vp); #else /* Check that the mountpoint passed in matches the one * from the vp that we are going to clear. Skip it otherwise. * We know from experience that this can happen when unmounting * loopback (bind) mounts. */ if (mnt != VTOVFSMNT(vp)) return; #endif /* Note that there is no mechanism for restoring the mount pointer * in the vnode if an error happens later on in the umount. This is * the only callback into the mvfs during umount. So far this has not * been a problem and if we don't do this here, the umount will never * succeed because the Linux code expects the mnt_count to be 2. * The count is 3 at this point from the initial allocation of the * vfsmnt structure, the path_lookup call in this umount call and * from when we placed the pointer in the vp. */ if (mnt == NULL) { MDKI_VFS_LOG(VFS_LOG_ERR, "%s: mnt is NULL\n", __FUNCTION__); return; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) mount_count = atomic_read(&mnt->mnt_count); #else # ifdef CONFIG_SMP br_read_lock(vfsmount_lock); for_each_possible_cpu(cpu) { mount_count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count; } br_read_unlock(vfsmount_lock); # else /* CONFIG_SMP */ mount_count = mnt->mnt_count; # endif /* else CONFIG_SMP */ #endif /* else < KERNEL_VERSION(2,6,38) */ if (mount_count == 3) { MDKI_MNTPUT(mnt); SET_VTOVFSMNT(vp, NULL); } }