diff options
| author | NeilBrown <neilb@suse.de> | 2007-02-14 00:33:12 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-14 08:09:53 -0800 | 
| commit | af6a4e280e3ff453653f39190b57b345ff0bec16 (patch) | |
| tree | 4895c90613737db7354f43431ed10a55dc0c98f0 | |
| parent | 982aedfd091e6d9831216f8519f12242091be4fd (diff) | |
| download | olio-linux-3.10-af6a4e280e3ff453653f39190b57b345ff0bec16.tar.xz olio-linux-3.10-af6a4e280e3ff453653f39190b57b345ff0bec16.zip  | |
[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>
| -rw-r--r-- | fs/nfsd/export.c | 106 | ||||
| -rw-r--r-- | fs/nfsd/nfs3xdr.c | 31 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 10 | ||||
| -rw-r--r-- | fs/nfsd/nfsfh.c | 88 | ||||
| -rw-r--r-- | fs/nfsd/nfsxdr.c | 19 | ||||
| -rw-r--r-- | include/linux/nfsd/export.h | 7 | ||||
| -rw-r--r-- | include/linux/nfsd/nfsd.h | 12 | ||||
| -rw-r--r-- | include/linux/nfsd/nfsfh.h | 99 | 
8 files changed, 242 insertions, 130 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 49c310b8492..bb3c314e247 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -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) diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index e695660921e..6f677988c71 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -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); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 18aa9440df1..0efba557fb5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -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) { diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 12c5e742137..286bc4d356f 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -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; +	} +} diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 6555c50d900..0c24b9e24fe 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -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); diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 045e38cdbe6..9f62d6182d3 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -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; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 4b7c4b568f6..72feac581aa 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -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 diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index d9c6c382165..11e568ee0ee 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -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;  	}  }  |