Commit af6a4e28 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] knfsd: add some new fsid types

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: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 982aedfd
...@@ -190,18 +190,17 @@ static int expkey_show(struct seq_file *m, ...@@ -190,18 +190,17 @@ static int expkey_show(struct seq_file *m,
struct cache_head *h) struct cache_head *h)
{ {
struct svc_expkey *ek ; struct svc_expkey *ek ;
int i;
if (h ==NULL) { if (h ==NULL) {
seq_puts(m, "#domain fsidtype fsid [path]\n"); seq_puts(m, "#domain fsidtype fsid [path]\n");
return 0; return 0;
} }
ek = container_of(h, struct svc_expkey, h); ek = container_of(h, struct svc_expkey, h);
seq_printf(m, "%s %d 0x%08x", ek->ek_client->name, seq_printf(m, "%s %d 0x", ek->ek_client->name,
ek->ek_fsidtype, ek->ek_fsid[0]); ek->ek_fsidtype);
if (ek->ek_fsidtype != 1) for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
seq_printf(m, "%08x", ek->ek_fsid[1]); seq_printf(m, "%08x", ek->ek_fsid[i]);
if (ek->ek_fsidtype == 2)
seq_printf(m, "%08x", ek->ek_fsid[2]);
if (test_bit(CACHE_VALID, &h->flags) && if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags)) { !test_bit(CACHE_NEGATIVE, &h->flags)) {
seq_printf(m, " "); seq_printf(m, " ");
...@@ -232,9 +231,8 @@ static inline void expkey_init(struct cache_head *cnew, ...@@ -232,9 +231,8 @@ static inline void expkey_init(struct cache_head *cnew,
kref_get(&item->ek_client->ref); kref_get(&item->ek_client->ref);
new->ek_client = item->ek_client; new->ek_client = item->ek_client;
new->ek_fsidtype = item->ek_fsidtype; new->ek_fsidtype = item->ek_fsidtype;
new->ek_fsid[0] = item->ek_fsid[0];
new->ek_fsid[1] = item->ek_fsid[1]; memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
new->ek_fsid[2] = item->ek_fsid[2];
} }
static inline void expkey_update(struct cache_head *cnew, static inline void expkey_update(struct cache_head *cnew,
...@@ -363,7 +361,7 @@ static struct svc_export *svc_export_update(struct svc_export *new, ...@@ -363,7 +361,7 @@ static struct svc_export *svc_export_update(struct svc_export *new,
struct svc_export *old); struct svc_export *old);
static struct svc_export *svc_export_lookup(struct svc_export *); 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. /* We currently export only dirs and regular files.
...@@ -376,12 +374,13 @@ static int check_export(struct inode *inode, int flags) ...@@ -376,12 +374,13 @@ static int check_export(struct inode *inode, int flags)
/* There are two requirements on a filesystem to be exportable. /* There are two requirements on a filesystem to be exportable.
* 1: We must be able to identify the filesystem from a number. * 1: We must be able to identify the filesystem from a number.
* either a device number (so FS_REQUIRES_DEV needed) * 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. * 2: We must be able to find an inode from a filehandle.
* This means that s_export_op must be set. * This means that s_export_op must be set.
*/ */
if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && 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"); dprintk("exp_export: export of non-dev fs without fsid\n");
return -EINVAL; return -EINVAL;
} }
...@@ -406,10 +405,6 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) ...@@ -406,10 +405,6 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
int len; int len;
int migrated, i, err; int migrated, i, err;
len = qword_get(mesg, buf, PAGE_SIZE);
if (len != 5 || memcmp(buf, "fsloc", 5))
return 0;
/* listsize */ /* listsize */
err = get_int(mesg, &fsloc->locations_count); err = get_int(mesg, &fsloc->locations_count);
if (err) if (err)
...@@ -520,6 +515,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -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.locations_count = 0;
exp.ex_fslocs.migrated = 0; exp.ex_fslocs.migrated = 0;
exp.ex_uuid = NULL;
/* flags */ /* flags */
err = get_int(&mesg, &an_int); err = get_int(&mesg, &an_int);
if (err == -ENOENT) if (err == -ENOENT)
...@@ -543,14 +540,35 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -543,14 +540,35 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
if (err) goto out; if (err) goto out;
exp.ex_fsid = an_int; exp.ex_fsid = an_int;
err = check_export(nd.dentry->d_inode, exp.ex_flags); while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
if (err) goto out; if (strcmp(buf, "fsloc") == 0)
err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); 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) if (err)
goto out; goto out;
} }
err = check_export(nd.dentry->d_inode, exp.ex_flags,
exp.ex_uuid);
if (err) goto out;
}
expp = svc_export_lookup(&exp); expp = svc_export_lookup(&exp);
if (expp) if (expp)
expp = svc_export_update(&exp, expp); expp = svc_export_update(&exp, expp);
...@@ -562,6 +580,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -562,6 +580,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
else else
exp_put(expp); exp_put(expp);
out: out:
nfsd4_fslocs_free(&exp.ex_fslocs);
kfree(exp.ex_uuid);
kfree(exp.ex_path); kfree(exp.ex_path);
if (nd.dentry) if (nd.dentry)
path_release(&nd); path_release(&nd);
...@@ -591,9 +611,19 @@ static int svc_export_show(struct seq_file *m, ...@@ -591,9 +611,19 @@ static int svc_export_show(struct seq_file *m,
seq_escape(m, exp->ex_client->name, " \t\n\\"); seq_escape(m, exp->ex_client->name, " \t\n\\");
seq_putc(m, '('); seq_putc(m, '(');
if (test_bit(CACHE_VALID, &h->flags) && 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_flags(m, exp->ex_flags, exp->ex_fsid,
exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); 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"); seq_puts(m, ")\n");
return 0; return 0;
} }
...@@ -630,6 +660,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) ...@@ -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_uid = item->ex_anon_uid;
new->ex_anon_gid = item->ex_anon_gid; new->ex_anon_gid = item->ex_anon_gid;
new->ex_fsid = item->ex_fsid; new->ex_fsid = item->ex_fsid;
new->ex_uuid = item->ex_uuid;
item->ex_uuid = NULL;
new->ex_path = item->ex_path; new->ex_path = item->ex_path;
item->ex_path = NULL; item->ex_path = NULL;
new->ex_fslocs.locations = item->ex_fslocs.locations; new->ex_fslocs.locations = item->ex_fslocs.locations;
...@@ -752,11 +784,11 @@ exp_get_key(svc_client *clp, dev_t dev, ino_t ino) ...@@ -752,11 +784,11 @@ exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
u32 fsidv[3]; u32 fsidv[3];
if (old_valid_dev(dev)) { if (old_valid_dev(dev)) {
mk_fsid_v0(fsidv, dev, ino); mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL);
return exp_find_key(clp, 0, fsidv, NULL); return exp_find_key(clp, FSID_DEV, fsidv, NULL);
} }
mk_fsid_v3(fsidv, dev, ino); mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL);
return exp_find_key(clp, 3, fsidv, NULL); return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL);
} }
/* /*
...@@ -767,9 +799,9 @@ exp_get_fsid_key(svc_client *clp, int fsid) ...@@ -767,9 +799,9 @@ exp_get_fsid_key(svc_client *clp, int fsid)
{ {
u32 fsidv[2]; 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 * svc_export *
...@@ -883,8 +915,8 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) ...@@ -883,8 +915,8 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
if ((exp->ex_flags & NFSEXP_FSID) == 0) if ((exp->ex_flags & NFSEXP_FSID) == 0)
return 0; return 0;
mk_fsid_v1(fsid, exp->ex_fsid); mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL);
return exp_set_key(clp, 1, fsid, exp); return exp_set_key(clp, FSID_NUM, fsid, exp);
} }
static int exp_hash(struct auth_domain *clp, struct svc_export *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) ...@@ -894,11 +926,11 @@ static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
dev_t dev = inode->i_sb->s_dev; dev_t dev = inode->i_sb->s_dev;
if (old_valid_dev(dev)) { if (old_valid_dev(dev)) {
mk_fsid_v0(fsid, dev, inode->i_ino); mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL);
return exp_set_key(clp, 0, fsid, exp); return exp_set_key(clp, FSID_DEV, fsid, exp);
} }
mk_fsid_v3(fsid, dev, inode->i_ino); mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL);
return exp_set_key(clp, 3, fsid, exp); return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp);
} }
static void exp_unhash(struct svc_export *exp) static void exp_unhash(struct svc_export *exp)
...@@ -977,7 +1009,7 @@ exp_export(struct nfsctl_export *nxp) ...@@ -977,7 +1009,7 @@ exp_export(struct nfsctl_export *nxp)
goto finish; 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; if (err) goto finish;
err = -ENOMEM; err = -ENOMEM;
...@@ -1170,9 +1202,9 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, ...@@ -1170,9 +1202,9 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
__be32 rv; __be32 rv;
u32 fsidv[2]; 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)) if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp)); return nfserrno(PTR_ERR(exp));
if (exp == NULL) if (exp == NULL)
......
...@@ -149,6 +149,27 @@ decode_sattr3(__be32 *p, struct iattr *iap) ...@@ -149,6 +149,27 @@ decode_sattr3(__be32 *p, struct iattr *iap)
return p; 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 * static __be32 *
encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat) struct kstat *stat)
...@@ -169,10 +190,7 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, ...@@ -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 = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
*p++ = htonl((u32) MAJOR(stat->rdev)); *p++ = htonl((u32) MAJOR(stat->rdev));
*p++ = htonl((u32) MINOR(stat->rdev)); *p++ = htonl((u32) MINOR(stat->rdev));
if (is_fsid(fhp, rqstp->rq_reffh)) p = encode_fsid(p, fhp);
p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
else
p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev));
p = xdr_encode_hyper(p, (u64) stat->ino); p = xdr_encode_hyper(p, (u64) stat->ino);
p = encode_time3(p, &stat->atime); p = encode_time3(p, &stat->atime);
lease_get_mtime(dentry->d_inode, &time); 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) ...@@ -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 = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
*p++ = fhp->fh_post_rdev[0]; *p++ = fhp->fh_post_rdev[0];
*p++ = fhp->fh_post_rdev[1]; *p++ = fhp->fh_post_rdev[1];
if (is_fsid(fhp, rqstp->rq_reffh)) p = encode_fsid(p, fhp);
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 = xdr_encode_hyper(p, (u64) inode->i_ino); p = xdr_encode_hyper(p, (u64) inode->i_ino);
p = encode_time3(p, &fhp->fh_post_atime); p = encode_time3(p, &fhp->fh_post_atime);
p = encode_time3(p, &fhp->fh_post_mtime); p = encode_time3(p, &fhp->fh_post_mtime);
......
...@@ -1563,14 +1563,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1563,14 +1563,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (exp->ex_fslocs.migrated) { if (exp->ex_fslocs.migrated) {
WRITE64(NFS4_REFERRAL_FSID_MAJOR); WRITE64(NFS4_REFERRAL_FSID_MAJOR);
WRITE64(NFS4_REFERRAL_FSID_MINOR); 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)exp->ex_fsid);
WRITE64((u64)0); WRITE64((u64)0);
} else { break;
case FSIDSOURCE_DEV:
WRITE32(0); WRITE32(0);
WRITE32(MAJOR(stat.dev)); WRITE32(MAJOR(stat.dev));
WRITE32(0); WRITE32(0);
WRITE32(MINOR(stat.dev)); WRITE32(MINOR(stat.dev));
break;
case FSIDSOURCE_UUID:
WRITEMEM(exp->ex_uuid, 16);
break;
} }
} }
if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
......
...@@ -119,9 +119,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -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)); 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) { if (!fhp->fh_dentry) {
__u32 *datap=NULL; __u32 *datap=NULL;
__u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */ __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) ...@@ -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; len = key_len(fh->fh_fsid_type) / 4;
if (len == 0) goto out; if (len == 0) goto out;
if (fh->fh_fsid_type == 2) { if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
/* deprecated, convert to type 3 */ /* deprecated, convert to type 3 */
len = 3; len = key_len(FSID_ENCODE_DEV)/4;
fh->fh_fsid_type = 3; 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[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
fh->fh_fsid[1] = fh->fh_fsid[2]; 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) ...@@ -164,8 +161,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
/* assume old filehandle format */ /* assume old filehandle format */
xdev = old_decode_dev(fh->ofh_xdev); xdev = old_decode_dev(fh->ofh_xdev);
xino = u32_to_ino_t(fh->ofh_xino); xino = u32_to_ino_t(fh->ofh_xino);
mk_fsid_v0(tfh, xdev, xino); mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle); exp = exp_find(rqstp->rq_client, FSID_DEV, tfh,
&rqstp->rq_chandle);
} }
if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN 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, ...@@ -334,6 +332,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
struct dentry *parent = dentry->d_parent; struct dentry *parent = dentry->d_parent;
__u32 *datap; __u32 *datap;
dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev; 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", dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
MAJOR(ex_dev), MINOR(ex_dev), MAJOR(ex_dev), MINOR(ex_dev),
...@@ -348,19 +347,31 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -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) { if (ref_fh && ref_fh->fh_export == exp) {
version = ref_fh->fh_handle.fh_version; version = ref_fh->fh_handle.fh_version;
if (version == 0xca) if (version == 0xca)
fsid_type = 0; fsid_type = FSID_DEV;
else else
fsid_type = ref_fh->fh_handle.fh_fsid_type; fsid_type = ref_fh->fh_handle.fh_fsid_type;
/* We know this version/type works for this export /* We know this version/type works for this export
* so there is no need for further checks. * 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) } else if (exp->ex_flags & NFSEXP_FSID)
fsid_type = 1; fsid_type = FSID_NUM;
else if (!old_valid_dev(ex_dev)) else if (!old_valid_dev(ex_dev))
/* for newer device numbers, we must use a newer fsid format */ /* for newer device numbers, we must use a newer fsid format */
fsid_type = 3; fsid_type = FSID_ENCODE_DEV;
else else
fsid_type = 0; fsid_type = FSID_DEV;
if (ref_fh == fhp) if (ref_fh == fhp)
fh_put(ref_fh); fh_put(ref_fh);
...@@ -396,36 +407,10 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -396,36 +407,10 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
fhp->fh_handle.fh_auth_type = 0; fhp->fh_handle.fh_auth_type = 0;
datap = fhp->fh_handle.fh_auth+0; datap = fhp->fh_handle.fh_auth+0;
fhp->fh_handle.fh_fsid_type = fsid_type; fhp->fh_handle.fh_fsid_type = fsid_type;
switch (fsid_type) { mk_fsid(fsid_type, datap, ex_dev,
case 0: exp->ex_dentry->d_inode->i_ino,
/* exp->ex_fsid, exp->ex_uuid);
* 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;
}
len = key_len(fsid_type); len = key_len(fsid_type);
datap += len/4; datap += len/4;
fhp->fh_handle.fh_size = 4 + len; fhp->fh_handle.fh_size = 4 + len;
...@@ -530,3 +515,22 @@ char * SVCFH_fmt(struct svc_fh *fhp) ...@@ -530,3 +515,22 @@ char * SVCFH_fmt(struct svc_fh *fhp)
fh->fh_base.fh_pad[5]); fh->fh_base.fh_pad[5]);
return buf; 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;
}
}
...@@ -153,6 +153,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, ...@@ -153,6 +153,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct dentry *dentry = fhp->fh_dentry; struct dentry *dentry = fhp->fh_dentry;
int type; int type;
struct timespec time; struct timespec time;
u32 f;
type = (stat->mode & S_IFMT); type = (stat->mode & S_IFMT);
...@@ -173,10 +174,22 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, ...@@ -173,10 +174,22 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
else else
*p++ = htonl(0xffffffff); *p++ = htonl(0xffffffff);
*p++ = htonl((u32) stat->blocks); *p++ = htonl((u32) stat->blocks);
if (is_fsid(fhp, rqstp->rq_reffh)) switch (fsid_source(fhp)) {
*p++ = htonl((u32) fhp->fh_export->ex_fsid); default:
else case FSIDSOURCE_DEV:
*p++ = htonl(new_encode_dev(stat->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->ino);
*p++ = htonl((u32) stat->atime.tv_sec); *p++ = htonl((u32) stat->atime.tv_sec);
*p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
......
...@@ -74,19 +74,20 @@ struct svc_export { ...@@ -74,19 +74,20 @@ struct svc_export {
uid_t ex_anon_uid; uid_t ex_anon_uid;
gid_t ex_anon_gid; gid_t ex_anon_gid;
int ex_fsid; int ex_fsid;
unsigned char * ex_uuid; /* 16 byte fsid */
struct nfsd4_fs_locations ex_fslocs; struct nfsd4_fs_locations ex_fslocs;
}; };
/* an "export key" (expkey) maps a filehandlefragement to an /* an "export key" (expkey) maps a filehandlefragement to an
* svc_export for a given client. There can be two per export, one * svc_export for a given client. There can be several per export,
* for type 0 (dev/ino), one for type 1 (fsid) * for the different fsid types.
*/ */
struct svc_expkey { struct svc_expkey {
struct cache_head h; struct cache_head h;
struct auth_domain * ek_client; struct auth_domain * ek_client;
int ek_fsidtype; int ek_fsidtype;
u32 ek_fsid[3]; u32 ek_fsid[6];
struct vfsmount * ek_mnt; struct vfsmount * ek_mnt;
struct dentry * ek_dentry; struct dentry * ek_dentry;
......
...@@ -254,18 +254,6 @@ void nfsd_lockd_shutdown(void); ...@@ -254,18 +254,6 @@ void nfsd_lockd_shutdown(void);
*/ */
extern struct timeval nfssvc_boot; 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 #ifdef CONFIG_NFSD_V4
/* before processing a COMPOUND operation, we have to check that there /* before processing a COMPOUND operation, we have to check that there
......
...@@ -165,38 +165,91 @@ typedef struct svc_fh { ...@@ -165,38 +165,91 @@ typedef struct svc_fh {
} svc_fh; } svc_fh;
static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t 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,
};
enum fsid_source {
FSIDSOURCE_DEV,
FSIDSOURCE_FSID,
FSIDSOURCE_UUID,
};
extern enum fsid_source fsid_source(struct svc_fh *fhp);
/* 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)
{ {
u32 *up;
switch(vers) {
case FSID_DEV:
fsidv[0] = htonl((MAJOR(dev)<<16) | fsidv[0] = htonl((MAJOR(dev)<<16) |
MINOR(dev)); MINOR(dev));
fsidv[1] = ino_t_to_u32(ino); fsidv[1] = ino_t_to_u32(ino);
} break;
case FSID_NUM:
static inline void mk_fsid_v1(u32 *fsidv, u32 fsid)
{
fsidv[0] = fsid; fsidv[0] = fsid;
} break;
case FSID_MAJOR_MINOR:
static inline void mk_fsid_v2(u32 *fsidv, dev_t dev, ino_t ino)
{
fsidv[0] = htonl(MAJOR(dev)); fsidv[0] = htonl(MAJOR(dev));
fsidv[1] = htonl(MINOR(dev)); fsidv[1] = htonl(MINOR(dev));
fsidv[2] = ino_t_to_u32(ino); fsidv[2] = ino_t_to_u32(ino);
} break;
static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino) case FSID_ENCODE_DEV:
{
fsidv[0] = new_encode_dev(dev); fsidv[0] = new_encode_dev(dev);
fsidv[1] = ino_t_to_u32(ino); 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) static inline int key_len(int type)
{ {
switch(type) { switch(type) {
case 0: return 8; case FSID_DEV: return 8;
case 1: return 4; case FSID_NUM: return 4;
case 2: return 12; case FSID_MAJOR_MINOR: return 12;
case 3: return 8; 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; default: return 0;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment