mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 00:51:35 +00:00
[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: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
982aedfd09
commit
af6a4e280e
8 changed files with 242 additions and 130 deletions
106
fs/nfsd/export.c
106
fs/nfsd/export.c
|
@ -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,
|
||||||
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,
|
||||||
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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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,12 +540,33 @@ 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);
|
||||||
|
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);
|
err = check_export(nd.dentry->d_inode, exp.ex_flags,
|
||||||
if (err)
|
exp.ex_uuid);
|
||||||
goto out;
|
if (err) goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
expp = svc_export_lookup(&exp);
|
expp = svc_export_lookup(&exp);
|
||||||
|
@ -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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
__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)
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
/* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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 {
|
||||||
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);
|
||||||
*/
|
*/
|
||||||
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 {
|
||||||
|
|
||||||
} svc_fh;
|
} svc_fh;
|
||||||
|
|
||||||
static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino)
|
enum nfsd_fsid {
|
||||||
{
|
FSID_DEV = 0,
|
||||||
fsidv[0] = htonl((MAJOR(dev)<<16) |
|
FSID_NUM,
|
||||||
MINOR(dev));
|
FSID_MAJOR_MINOR,
|
||||||
fsidv[1] = ino_t_to_u32(ino);
|
FSID_ENCODE_DEV,
|
||||||
}
|
FSID_UUID4_INUM,
|
||||||
|
FSID_UUID8,
|
||||||
|
FSID_UUID16,
|
||||||
|
FSID_UUID16_INUM,
|
||||||
|
};
|
||||||
|
|
||||||
static inline void mk_fsid_v1(u32 *fsidv, u32 fsid)
|
enum fsid_source {
|
||||||
{
|
FSIDSOURCE_DEV,
|
||||||
fsidv[0] = fsid;
|
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);
|
u32 *up;
|
||||||
fsidv[1] = ino_t_to_u32(ino);
|
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)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue