[PATCH] knfsd: add some new fsid types
authorNeilBrown <neilb@suse.de>
Wed, 14 Feb 2007 08:33:12 +0000 (00:33 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 14 Feb 2007 16:09:53 +0000 (08:09 -0800)
Add support for using a filesystem UUID to identify and export point in the
filehandle.

For NFSv2, this UUID is xor-ed down to 4 or 8 bytes so that it doesn't take up
too much room.  For NFSv3+, we use the full 16 bytes, and possibly also a
64bit inode number for exports beneath the root of a filesystem.

When generating an fsid to return in 'stat' information, use the UUID (hashed
down to size) if it is available and a small 'fsid' was not specifically
provided.

Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/nfsd/export.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsxdr.c
include/linux/nfsd/export.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/nfsfh.h

index 49c310b849239cecc236c9a039352ea40cffa728..bb3c314e2479543e83a0a4a66e3bffd01197f726 100644 (file)
@@ -190,18 +190,17 @@ static int expkey_show(struct seq_file *m,
                       struct cache_head *h)
 {
        struct svc_expkey *ek ;
+       int i;
 
        if (h ==NULL) {
                seq_puts(m, "#domain fsidtype fsid [path]\n");
                return 0;
        }
        ek = container_of(h, struct svc_expkey, h);
-       seq_printf(m, "%s %d 0x%08x", ek->ek_client->name,
-                  ek->ek_fsidtype, ek->ek_fsid[0]);
-       if (ek->ek_fsidtype != 1)
-               seq_printf(m, "%08x", ek->ek_fsid[1]);
-       if (ek->ek_fsidtype == 2)
-               seq_printf(m, "%08x", ek->ek_fsid[2]);
+       seq_printf(m, "%s %d 0x", ek->ek_client->name,
+                  ek->ek_fsidtype);
+       for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
+               seq_printf(m, "%08x", ek->ek_fsid[i]);
        if (test_bit(CACHE_VALID, &h->flags) && 
            !test_bit(CACHE_NEGATIVE, &h->flags)) {
                seq_printf(m, " ");
@@ -232,9 +231,8 @@ static inline void expkey_init(struct cache_head *cnew,
        kref_get(&item->ek_client->ref);
        new->ek_client = item->ek_client;
        new->ek_fsidtype = item->ek_fsidtype;
-       new->ek_fsid[0] = item->ek_fsid[0];
-       new->ek_fsid[1] = item->ek_fsid[1];
-       new->ek_fsid[2] = item->ek_fsid[2];
+
+       memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
 }
 
 static inline void expkey_update(struct cache_head *cnew,
@@ -363,7 +361,7 @@ static struct svc_export *svc_export_update(struct svc_export *new,
                                            struct svc_export *old);
 static struct svc_export *svc_export_lookup(struct svc_export *);
 
-static int check_export(struct inode *inode, int flags)
+static int check_export(struct inode *inode, int flags, unsigned char *uuid)
 {
 
        /* We currently export only dirs and regular files.
@@ -376,12 +374,13 @@ static int check_export(struct inode *inode, int flags)
        /* There are two requirements on a filesystem to be exportable.
         * 1:  We must be able to identify the filesystem from a number.
         *       either a device number (so FS_REQUIRES_DEV needed)
-        *       or an FSID number (so NFSEXP_FSID needed).
+        *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
         * 2:  We must be able to find an inode from a filehandle.
         *       This means that s_export_op must be set.
         */
        if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
-           !(flags & NFSEXP_FSID)) {
+           !(flags & NFSEXP_FSID) &&
+           uuid == NULL) {
                dprintk("exp_export: export of non-dev fs without fsid\n");
                return -EINVAL;
        }
@@ -406,10 +405,6 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
        int len;
        int migrated, i, err;
 
-       len = qword_get(mesg, buf, PAGE_SIZE);
-       if (len != 5 || memcmp(buf, "fsloc", 5))
-               return 0;
-
        /* listsize */
        err = get_int(mesg, &fsloc->locations_count);
        if (err)
@@ -520,6 +515,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
        exp.ex_fslocs.locations_count = 0;
        exp.ex_fslocs.migrated = 0;
 
+       exp.ex_uuid = NULL;
+
        /* flags */
        err = get_int(&mesg, &an_int);
        if (err == -ENOENT)
@@ -543,12 +540,33 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
                if (err) goto out;
                exp.ex_fsid = an_int;
 
-               err = check_export(nd.dentry->d_inode, exp.ex_flags);
-               if (err) goto out;
+               while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
+                       if (strcmp(buf, "fsloc") == 0)
+                               err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
+                       else if (strcmp(buf, "uuid") == 0) {
+                               /* expect a 16 byte uuid encoded as \xXXXX... */
+                               len = qword_get(&mesg, buf, PAGE_SIZE);
+                               if (len != 16)
+                                       err  = -EINVAL;
+                               else {
+                                       exp.ex_uuid =
+                                               kmemdup(buf, 16, GFP_KERNEL);
+                                       if (exp.ex_uuid == NULL)
+                                               err = -ENOMEM;
+                               }
+                       } else
+                               /* quietly ignore unknown words and anything
+                                * following. Newer user-space can try to set
+                                * new values, then see what the result was.
+                                */
+                               break;
+                       if (err)
+                               goto out;
+               }
 
-               err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
-               if (err)
-                       goto out;
+               err = check_export(nd.dentry->d_inode, exp.ex_flags,
+                                  exp.ex_uuid);
+               if (err) goto out;
        }
 
        expp = svc_export_lookup(&exp);
@@ -562,6 +580,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
        else
                exp_put(expp);
  out:
+       nfsd4_fslocs_free(&exp.ex_fslocs);
+       kfree(exp.ex_uuid);
        kfree(exp.ex_path);
        if (nd.dentry)
                path_release(&nd);
@@ -591,9 +611,19 @@ static int svc_export_show(struct seq_file *m,
        seq_escape(m, exp->ex_client->name, " \t\n\\");
        seq_putc(m, '(');
        if (test_bit(CACHE_VALID, &h->flags) && 
-           !test_bit(CACHE_NEGATIVE, &h->flags))
+           !test_bit(CACHE_NEGATIVE, &h->flags)) {
                exp_flags(m, exp->ex_flags, exp->ex_fsid,
                          exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
+               if (exp->ex_uuid) {
+                       int i;
+                       seq_puts(m, ",uuid=");
+                       for (i=0; i<16; i++) {
+                               if ((i&3) == 0 && i)
+                                       seq_putc(m, ':');
+                               seq_printf(m, "%02x", exp->ex_uuid[i]);
+                       }
+               }
+       }
        seq_puts(m, ")\n");
        return 0;
 }
@@ -630,6 +660,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
        new->ex_anon_uid = item->ex_anon_uid;
        new->ex_anon_gid = item->ex_anon_gid;
        new->ex_fsid = item->ex_fsid;
+       new->ex_uuid = item->ex_uuid;
+       item->ex_uuid = NULL;
        new->ex_path = item->ex_path;
        item->ex_path = NULL;
        new->ex_fslocs.locations = item->ex_fslocs.locations;
@@ -752,11 +784,11 @@ exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
        u32 fsidv[3];
        
        if (old_valid_dev(dev)) {
-               mk_fsid_v0(fsidv, dev, ino);
-               return exp_find_key(clp, 0, fsidv, NULL);
+               mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL);
+               return exp_find_key(clp, FSID_DEV, fsidv, NULL);
        }
-       mk_fsid_v3(fsidv, dev, ino);
-       return exp_find_key(clp, 3, fsidv, NULL);
+       mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL);
+       return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL);
 }
 
 /*
@@ -767,9 +799,9 @@ exp_get_fsid_key(svc_client *clp, int fsid)
 {
        u32 fsidv[2];
 
-       mk_fsid_v1(fsidv, fsid);
+       mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL);
 
-       return exp_find_key(clp, 1, fsidv, NULL);
+       return exp_find_key(clp, FSID_NUM, fsidv, NULL);
 }
 
 svc_export *
@@ -883,8 +915,8 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
        if ((exp->ex_flags & NFSEXP_FSID) == 0)
                return 0;
 
-       mk_fsid_v1(fsid, exp->ex_fsid);
-       return exp_set_key(clp, 1, fsid, exp);
+       mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL);
+       return exp_set_key(clp, FSID_NUM, fsid, exp);
 }
 
 static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
@@ -894,11 +926,11 @@ static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
        dev_t dev = inode->i_sb->s_dev;
 
        if (old_valid_dev(dev)) {
-               mk_fsid_v0(fsid, dev, inode->i_ino);
-               return exp_set_key(clp, 0, fsid, exp);
+               mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL);
+               return exp_set_key(clp, FSID_DEV, fsid, exp);
        }
-       mk_fsid_v3(fsid, dev, inode->i_ino);
-       return exp_set_key(clp, 3, fsid, exp);
+       mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL);
+       return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp);
 }
 
 static void exp_unhash(struct svc_export *exp)
@@ -977,7 +1009,7 @@ exp_export(struct nfsctl_export *nxp)
                goto finish;
        }
 
-       err = check_export(nd.dentry->d_inode, nxp->ex_flags);
+       err = check_export(nd.dentry->d_inode, nxp->ex_flags, NULL);
        if (err) goto finish;
 
        err = -ENOMEM;
@@ -1170,9 +1202,9 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
        __be32 rv;
        u32 fsidv[2];
 
-       mk_fsid_v1(fsidv, 0);
+       mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
 
-       exp = exp_find(clp, 1, fsidv, creq);
+       exp = exp_find(clp, FSID_NUM, fsidv, creq);
        if (IS_ERR(exp))
                return nfserrno(PTR_ERR(exp));
        if (exp == NULL)
index e695660921ec30adfd6f0ebb3546120ee536964e..6f677988c71d74c60edcda3002233ffba9d807ed 100644 (file)
@@ -149,6 +149,27 @@ decode_sattr3(__be32 *p, struct iattr *iap)
        return p;
 }
 
+static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
+{
+       u64 f;
+       switch(fsid_source(fhp)) {
+       default:
+       case FSIDSOURCE_DEV:
+               p = xdr_encode_hyper(p, (u64)huge_encode_dev
+                                    (fhp->fh_dentry->d_inode->i_sb->s_dev));
+               break;
+       case FSIDSOURCE_FSID:
+               p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
+               break;
+       case FSIDSOURCE_UUID:
+               f = ((u64*)fhp->fh_export->ex_uuid)[0];
+               f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
+               p = xdr_encode_hyper(p, f);
+               break;
+       }
+       return p;
+}
+
 static __be32 *
 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
              struct kstat *stat)
@@ -169,10 +190,7 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
        *p++ = htonl((u32) MAJOR(stat->rdev));
        *p++ = htonl((u32) MINOR(stat->rdev));
-       if (is_fsid(fhp, rqstp->rq_reffh))
-               p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
-       else
-               p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev));
+       p = encode_fsid(p, fhp);
        p = xdr_encode_hyper(p, (u64) stat->ino);
        p = encode_time3(p, &stat->atime);
        lease_get_mtime(dentry->d_inode, &time); 
@@ -203,10 +221,7 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
        p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
        *p++ = fhp->fh_post_rdev[0];
        *p++ = fhp->fh_post_rdev[1];
-       if (is_fsid(fhp, rqstp->rq_reffh))
-               p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
-       else
-               p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev));
+       p = encode_fsid(p, fhp);
        p = xdr_encode_hyper(p, (u64) inode->i_ino);
        p = encode_time3(p, &fhp->fh_post_atime);
        p = encode_time3(p, &fhp->fh_post_mtime);
index 18aa9440df14400eaf63f3d2d7cdedfff8b1952d..0efba557fb55b9b84ed801e6b57757b1883c075b 100644 (file)
@@ -1563,14 +1563,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                if (exp->ex_fslocs.migrated) {
                        WRITE64(NFS4_REFERRAL_FSID_MAJOR);
                        WRITE64(NFS4_REFERRAL_FSID_MINOR);
-               } else if (is_fsid(fhp, rqstp->rq_reffh)) {
+               } else switch(fsid_source(fhp)) {
+               case FSIDSOURCE_FSID:
                        WRITE64((u64)exp->ex_fsid);
                        WRITE64((u64)0);
-               } else {
+                       break;
+               case FSIDSOURCE_DEV:
                        WRITE32(0);
                        WRITE32(MAJOR(stat.dev));
                        WRITE32(0);
                        WRITE32(MINOR(stat.dev));
+                       break;
+               case FSIDSOURCE_UUID:
+                       WRITEMEM(exp->ex_uuid, 16);
+                       break;
                }
        }
        if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
index 12c5e74213740ead8f248ba1f92061876158c264..286bc4d356f4b5963bd739a9997026beb6b71efb 100644 (file)
@@ -119,9 +119,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 
        dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
-       /* keep this filehandle for possible reference  when encoding attributes */
-       rqstp->rq_reffh = fh;
-
        if (!fhp->fh_dentry) {
                __u32 *datap=NULL;
                __u32 tfh[3];           /* filehandle fragment for oldstyle filehandles */
@@ -146,10 +143,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        }
                        len = key_len(fh->fh_fsid_type) / 4;
                        if (len == 0) goto out;
-                       if  (fh->fh_fsid_type == 2) {
+                       if  (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
                                /* deprecated, convert to type 3 */
-                               len = 3;
-                               fh->fh_fsid_type = 3;
+                               len = key_len(FSID_ENCODE_DEV)/4;
+                               fh->fh_fsid_type = FSID_ENCODE_DEV;
                                fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
                                fh->fh_fsid[1] = fh->fh_fsid[2];
                        }
@@ -164,8 +161,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        /* assume old filehandle format */
                        xdev = old_decode_dev(fh->ofh_xdev);
                        xino = u32_to_ino_t(fh->ofh_xino);
-                       mk_fsid_v0(tfh, xdev, xino);
-                       exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle);
+                       mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
+                       exp = exp_find(rqstp->rq_client, FSID_DEV, tfh,
+                                      &rqstp->rq_chandle);
                }
 
                if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
@@ -334,6 +332,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
        struct dentry *parent = dentry->d_parent;
        __u32 *datap;
        dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev;
+       int root_export = (exp->ex_dentry == exp->ex_dentry->d_sb->s_root);
 
        dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
                MAJOR(ex_dev), MINOR(ex_dev),
@@ -348,19 +347,31 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
        if (ref_fh && ref_fh->fh_export == exp) {
                version = ref_fh->fh_handle.fh_version;
                if (version == 0xca)
-                       fsid_type = 0;
+                       fsid_type = FSID_DEV;
                else
                        fsid_type = ref_fh->fh_handle.fh_fsid_type;
                /* We know this version/type works for this export
                 * so there is no need for further checks.
                 */
+       } else if (exp->ex_uuid) {
+               if (fhp->fh_maxsize >= 64) {
+                       if (root_export)
+                               fsid_type = FSID_UUID16;
+                       else
+                               fsid_type = FSID_UUID16_INUM;
+               } else {
+                       if (root_export)
+                               fsid_type = FSID_UUID8;
+                       else
+                               fsid_type = FSID_UUID4_INUM;
+               }
        } else if (exp->ex_flags & NFSEXP_FSID)
-               fsid_type = 1;
+               fsid_type = FSID_NUM;
        else if (!old_valid_dev(ex_dev))
                /* for newer device numbers, we must use a newer fsid format */
-               fsid_type = 3;
+               fsid_type = FSID_ENCODE_DEV;
        else
-               fsid_type = 0;
+               fsid_type = FSID_DEV;
 
        if (ref_fh == fhp)
                fh_put(ref_fh);
@@ -396,36 +407,10 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
                fhp->fh_handle.fh_auth_type = 0;
                datap = fhp->fh_handle.fh_auth+0;
                fhp->fh_handle.fh_fsid_type = fsid_type;
-               switch (fsid_type) {
-               case 0:
-                       /*
-                        * fsid_type 0:
-                        * 2byte major, 2byte minor, 4byte inode
-                        */
-                       mk_fsid_v0(datap, ex_dev,
-                                  exp->ex_dentry->d_inode->i_ino);
-                       break;
-               case 1:
-                       /* fsid_type 1 == 4 bytes filesystem id */
-                       mk_fsid_v1(datap, exp->ex_fsid);
-                       break;
-               case 2:
-                       /*
-                        * fsid_type 2:
-                        * 4byte major, 4byte minor, 4byte inode
-                        */
-                       mk_fsid_v2(datap, ex_dev,
-                                  exp->ex_dentry->d_inode->i_ino);
-                       break;
-               case 3:
-                       /*
-                        * fsid_type 3:
-                        * 4byte devicenumber, 4byte inode
-                        */
-                       mk_fsid_v3(datap, ex_dev,
-                                  exp->ex_dentry->d_inode->i_ino);
-                       break;
-               }
+               mk_fsid(fsid_type, datap, ex_dev,
+                       exp->ex_dentry->d_inode->i_ino,
+                       exp->ex_fsid, exp->ex_uuid);
+
                len = key_len(fsid_type);
                datap += len/4;
                fhp->fh_handle.fh_size = 4 + len;
@@ -530,3 +515,22 @@ char * SVCFH_fmt(struct svc_fh *fhp)
                fh->fh_base.fh_pad[5]);
        return buf;
 }
+
+enum fsid_source fsid_source(struct svc_fh *fhp)
+{
+       if (fhp->fh_handle.fh_version != 1)
+               return FSIDSOURCE_DEV;
+       switch(fhp->fh_handle.fh_fsid_type) {
+       case FSID_DEV:
+       case FSID_ENCODE_DEV:
+       case FSID_MAJOR_MINOR:
+               return FSIDSOURCE_DEV;
+       case FSID_NUM:
+               return FSIDSOURCE_FSID;
+       default:
+               if (fhp->fh_export->ex_flags & NFSEXP_FSID)
+                       return FSIDSOURCE_FSID;
+               else
+                       return FSIDSOURCE_UUID;
+       }
+}
index 6555c50d9006966f37f659f39e837c30a53c7c03..0c24b9e24fe866683a357f1a9e8b08bcb2fbe30c 100644 (file)
@@ -153,6 +153,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        struct dentry   *dentry = fhp->fh_dentry;
        int type;
        struct timespec time;
+       u32 f;
 
        type = (stat->mode & S_IFMT);
 
@@ -173,10 +174,22 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        else
                *p++ = htonl(0xffffffff);
        *p++ = htonl((u32) stat->blocks);
-       if (is_fsid(fhp, rqstp->rq_reffh))
-               *p++ = htonl((u32) fhp->fh_export->ex_fsid);
-       else
+       switch (fsid_source(fhp)) {
+       default:
+       case FSIDSOURCE_DEV:
                *p++ = htonl(new_encode_dev(stat->dev));
+               break;
+       case FSIDSOURCE_FSID:
+               *p++ = htonl((u32) fhp->fh_export->ex_fsid);
+               break;
+       case FSIDSOURCE_UUID:
+               f = ((u32*)fhp->fh_export->ex_uuid)[0];
+               f ^= ((u32*)fhp->fh_export->ex_uuid)[1];
+               f ^= ((u32*)fhp->fh_export->ex_uuid)[2];
+               f ^= ((u32*)fhp->fh_export->ex_uuid)[3];
+               *p++ = htonl(f);
+               break;
+       }
        *p++ = htonl((u32) stat->ino);
        *p++ = htonl((u32) stat->atime.tv_sec);
        *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
index 045e38cdbe646f966abf370cddb8d573b4770d62..9f62d6182d32824b3e9f8afd22b01532b98680af 100644 (file)
@@ -74,19 +74,20 @@ struct svc_export {
        uid_t                   ex_anon_uid;
        gid_t                   ex_anon_gid;
        int                     ex_fsid;
+       unsigned char *         ex_uuid; /* 16 byte fsid */
        struct nfsd4_fs_locations ex_fslocs;
 };
 
 /* an "export key" (expkey) maps a filehandlefragement to an
- * svc_export for a given client.  There can be two per export, one
- * for type 0 (dev/ino), one for type 1 (fsid)
+ * svc_export for a given client.  There can be several per export,
+ * for the different fsid types.
  */
 struct svc_expkey {
        struct cache_head       h;
 
        struct auth_domain *    ek_client;
        int                     ek_fsidtype;
-       u32                     ek_fsid[3];
+       u32                     ek_fsid[6];
 
        struct vfsmount *       ek_mnt;
        struct dentry *         ek_dentry;
index 4b7c4b568f6d685fbe53ab231f459c477d3f9e3a..72feac581aa354572b89fd3d5d3e9feb8839fe5c 100644 (file)
@@ -254,18 +254,6 @@ void               nfsd_lockd_shutdown(void);
  */
 extern struct timeval  nfssvc_boot;
 
-static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh)
-{
-       if (fh->fh_export->ex_flags & NFSEXP_FSID) {
-               struct vfsmount *mnt = fh->fh_export->ex_mnt;
-               if (!old_valid_dev(mnt->mnt_sb->s_dev) ||
-                   (reffh->fh_version == 1 && reffh->fh_fsid_type == 1))
-                       return 1;
-       }
-       return 0;
-}
-
-
 #ifdef CONFIG_NFSD_V4
 
 /* before processing a COMPOUND operation, we have to check that there
index d9c6c382165dd23165d025ae4cd044db9dcf7f8b..11e568ee0eeb877b69ea1e78f320f203bffb6a39 100644 (file)
@@ -165,38 +165,91 @@ typedef struct svc_fh {
 
 } svc_fh;
 
-static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino)
-{
-       fsidv[0] = htonl((MAJOR(dev)<<16) |
-                       MINOR(dev));
-       fsidv[1] = ino_t_to_u32(ino);
-}
+enum nfsd_fsid {
+       FSID_DEV = 0,
+       FSID_NUM,
+       FSID_MAJOR_MINOR,
+       FSID_ENCODE_DEV,
+       FSID_UUID4_INUM,
+       FSID_UUID8,
+       FSID_UUID16,
+       FSID_UUID16_INUM,
+};
 
-static inline void mk_fsid_v1(u32 *fsidv, u32 fsid)
-{
-       fsidv[0] = fsid;
-}
+enum fsid_source {
+       FSIDSOURCE_DEV,
+       FSIDSOURCE_FSID,
+       FSIDSOURCE_UUID,
+};
+extern enum fsid_source fsid_source(struct svc_fh *fhp);
 
-static inline void mk_fsid_v2(u32 *fsidv, dev_t dev, ino_t ino)
-{
-       fsidv[0] = htonl(MAJOR(dev));
-       fsidv[1] = htonl(MINOR(dev));
-       fsidv[2] = ino_t_to_u32(ino);
-}
 
-static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino)
+/* This might look a little large to "inline" but in all calls except
+ * one, 'vers' is constant so moste of the function disappears.
+ */
+static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
+                          u32 fsid, unsigned char *uuid)
 {
-       fsidv[0] = new_encode_dev(dev);
-       fsidv[1] = ino_t_to_u32(ino);
+       u32 *up;
+       switch(vers) {
+       case FSID_DEV:
+               fsidv[0] = htonl((MAJOR(dev)<<16) |
+                                MINOR(dev));
+               fsidv[1] = ino_t_to_u32(ino);
+               break;
+       case FSID_NUM:
+               fsidv[0] = fsid;
+               break;
+       case FSID_MAJOR_MINOR:
+               fsidv[0] = htonl(MAJOR(dev));
+               fsidv[1] = htonl(MINOR(dev));
+               fsidv[2] = ino_t_to_u32(ino);
+               break;
+
+       case FSID_ENCODE_DEV:
+               fsidv[0] = new_encode_dev(dev);
+               fsidv[1] = ino_t_to_u32(ino);
+               break;
+
+       case FSID_UUID4_INUM:
+               /* 4 byte fsid and inode number */
+               up = (u32*)uuid;
+               fsidv[0] = ino_t_to_u32(ino);
+               fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3];
+               break;
+
+       case FSID_UUID8:
+               /* 8 byte fsid  */
+               up = (u32*)uuid;
+               fsidv[0] = up[0] ^ up[2];
+               fsidv[1] = up[1] ^ up[3];
+               break;
+
+       case FSID_UUID16:
+               /* 16 byte fsid - NFSv3+ only */
+               memcpy(fsidv, uuid, 16);
+               break;
+
+       case FSID_UUID16_INUM:
+               /* 8 byte inode and 16 byte fsid */
+               *(u64*)fsidv = (u64)ino;
+               memcpy(fsidv+2, uuid, 16);
+               break;
+       default: BUG();
+       }
 }
 
 static inline int key_len(int type)
 {
        switch(type) {
-       case 0: return 8;
-       case 1: return 4;
-       case 2: return 12;
-       case 3: return 8;
+       case FSID_DEV:          return 8;
+       case FSID_NUM:          return 4;
+       case FSID_MAJOR_MINOR:  return 12;
+       case FSID_ENCODE_DEV:   return 8;
+       case FSID_UUID4_INUM:   return 8;
+       case FSID_UUID8:        return 8;
+       case FSID_UUID16:       return 16;
+       case FSID_UUID16_INUM:  return 24;
        default: return 0;
        }
 }