Skip to content

Commit

Permalink
[PATCH] knfsd: add some new fsid types
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
neilbrown authored and Linus Torvalds committed Feb 14, 2007
1 parent 982aedf commit af6a4e2
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 130 deletions.
106 changes: 69 additions & 37 deletions fs/nfsd/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, " ");
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

/*
Expand All @@ -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 *
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
31 changes: 23 additions & 8 deletions fs/nfsd/nfs3xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions fs/nfsd/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit af6a4e2

Please sign in to comment.