Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #4
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}
Exemple #8
0
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));
}
Exemple #9
0
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;
}
Exemple #10
0
/*
 * 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;
}
Exemple #11
0
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);
}
Exemple #12
0
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) */
}
Exemple #13
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;
}
Exemple #14
0
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);
    }
}