From af6a4e280e3ff453653f39190b57b345ff0bec16 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 14 Feb 2007 00:33:12 -0800 Subject: [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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/nfsd/export.h | 7 ++-- include/linux/nfsd/nfsd.h | 12 ------ include/linux/nfsd/nfsfh.h | 99 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 80 insertions(+), 38 deletions(-) (limited to 'include') 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; } } -- cgit v1.2.3