Commit 9e213524 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] prepare for 32-bit dev_t: NFS

	NFS made dev_t-agnostic.  Aside of minor fixes in debugging printks,
and adding old_encode_dev()/old_decode_dev(), the main part is in handling
of exports with large dev_t.  New fhandle format introduced, fh_verify(),
fh_compose() and exports cache taught to deal with it.  Format is used when
->s_dev of exported fs doesn't fit into 256:256; in that case we put major
and minor in separate words in fhandle; ->fh_fsid_type is set to 2.
parent 7f904771
...@@ -651,7 +651,8 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, ...@@ -651,7 +651,8 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
default: return -EINVAL; default: return -EINVAL;
} }
dprintk("NFS call mknod %s %x\n", name->name, (unsigned)rdev); dprintk("NFS call mknod %s %u:%u\n", name->name,
MAJOR(rdev), MINOR(rdev));
dir_attr.valid = 0; dir_attr.valid = 0;
fattr->valid = 0; fattr->valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
......
...@@ -1503,7 +1503,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, ...@@ -1503,7 +1503,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
READ32(major); READ32(major);
READ32(minor); READ32(minor);
nfp->rdev = MKDEV(major, minor); nfp->rdev = MKDEV(major, minor);
dprintk("read_attrs: rdev=0x%x\n", nfp->rdev); dprintk("read_attrs: rdev=%u:%u\n", major, minor);
} }
if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
READ_BUF(8); READ_BUF(8);
......
...@@ -277,7 +277,7 @@ nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, ...@@ -277,7 +277,7 @@ nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
sattr->ia_valid &= ~ATTR_SIZE; sattr->ia_valid &= ~ATTR_SIZE;
} else if (S_ISCHR(mode) || S_ISBLK(mode)) { } else if (S_ISCHR(mode) || S_ISBLK(mode)) {
sattr->ia_valid |= ATTR_SIZE; sattr->ia_valid |= ATTR_SIZE;
sattr->ia_size = rdev; /* get out your barf bag */ sattr->ia_size = old_encode_dev(rdev);/* get out your barf bag */
} }
fattr->valid = 0; fattr->valid = 0;
......
...@@ -55,11 +55,16 @@ static int exp_verify_string(char *cp, int max); ...@@ -55,11 +55,16 @@ static int exp_verify_string(char *cp, int max);
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
static struct cache_head *expkey_table[EXPKEY_HASHMAX]; static struct cache_head *expkey_table[EXPKEY_HASHMAX];
static inline int key_len(int type)
{
return type == 0 ? 8 : type == 1 ? 4 : 12;
}
static inline int svc_expkey_hash(struct svc_expkey *item) static inline int svc_expkey_hash(struct svc_expkey *item)
{ {
int hash = item->ek_fsidtype; int hash = item->ek_fsidtype;
char * cp = (char*)item->ek_fsid; char * cp = (char*)item->ek_fsid;
int len = (item->ek_fsidtype==0)?8:4; int len = key_len(item->ek_fsidtype);
hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
...@@ -89,7 +94,7 @@ void expkey_request(struct cache_detail *cd, ...@@ -89,7 +94,7 @@ void expkey_request(struct cache_detail *cd,
qword_add(bpp, blen, ek->ek_client->name); qword_add(bpp, blen, ek->ek_client->name);
snprintf(type, 5, "%d", ek->ek_fsidtype); snprintf(type, 5, "%d", ek->ek_fsidtype);
qword_add(bpp, blen, type); qword_add(bpp, blen, type);
qword_addhex(bpp, blen, (char*)ek->ek_fsid, ek->ek_fsidtype==0?8:4); qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
(*bpp)[-1] = '\n'; (*bpp)[-1] = '\n';
} }
...@@ -130,12 +135,12 @@ int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -130,12 +135,12 @@ int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
if (*ep) if (*ep)
goto out; goto out;
dprintk("found fsidtype %d\n", fsidtype); dprintk("found fsidtype %d\n", fsidtype);
if (fsidtype > 1) if (fsidtype > 2)
goto out; goto out;
if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
goto out; goto out;
dprintk("found fsid length %d\n", len); dprintk("found fsid length %d\n", len);
if (len != ((fsidtype==0)?8:4)) if (len != key_len(fsidtype))
goto out; goto out;
/* OK, we seem to have a valid key */ /* OK, we seem to have a valid key */
...@@ -206,8 +211,10 @@ static int expkey_show(struct seq_file *m, ...@@ -206,8 +211,10 @@ static int expkey_show(struct seq_file *m,
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%08x", ek->ek_client->name,
ek->ek_fsidtype, ek->ek_fsid[0]); ek->ek_fsidtype, ek->ek_fsid[0]);
if (ek->ek_fsid == 0) if (ek->ek_fsidtype != 1)
seq_printf(m, "%08x", ek->ek_fsid[0]); seq_printf(m, "%08x", ek->ek_fsid[1]);
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, " ");
...@@ -230,13 +237,8 @@ struct cache_detail svc_expkey_cache = { ...@@ -230,13 +237,8 @@ struct cache_detail svc_expkey_cache = {
static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b) static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
{ {
if (a->ek_fsidtype != b->ek_fsidtype || if (a->ek_fsidtype != b->ek_fsidtype ||
a->ek_client != b->ek_client) a->ek_client != b->ek_client ||
return 0; memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0)
if (a->ek_fsid[0] != b->ek_fsid[0])
return 0;
if (a->ek_fsidtype == 1)
return 1;
if (a->ek_fsid[1] != b->ek_fsid[1])
return 0; return 0;
return 1; return 1;
} }
...@@ -248,6 +250,7 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it ...@@ -248,6 +250,7 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it
new->ek_fsidtype = item->ek_fsidtype; new->ek_fsidtype = item->ek_fsidtype;
new->ek_fsid[0] = item->ek_fsid[0]; new->ek_fsid[0] = item->ek_fsid[0];
new->ek_fsid[1] = item->ek_fsid[1]; new->ek_fsid[1] = item->ek_fsid[1];
new->ek_fsid[2] = item->ek_fsid[2];
} }
static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
...@@ -502,8 +505,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) ...@@ -502,8 +505,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
key.ek_client = clp; key.ek_client = clp;
key.ek_fsidtype = fsid_type; key.ek_fsidtype = fsid_type;
key.ek_fsid[0] = fsidv[0]; memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
key.ek_fsid[1] = fsidv[1];
ek = svc_expkey_lookup(&key, 0); ek = svc_expkey_lookup(&key, 0);
if (ek != NULL) if (ek != NULL)
...@@ -519,8 +521,7 @@ int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, ...@@ -519,8 +521,7 @@ int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
key.ek_client = clp; key.ek_client = clp;
key.ek_fsidtype = fsid_type; key.ek_fsidtype = fsid_type;
key.ek_fsid[0] = fsidv[0]; memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
key.ek_fsid[1] = fsidv[1];
key.ek_export = exp; key.ek_export = exp;
key.h.expiry_time = NEVER; key.h.expiry_time = NEVER;
key.h.flags = 0; key.h.flags = 0;
...@@ -539,10 +540,14 @@ int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, ...@@ -539,10 +540,14 @@ int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
static inline struct svc_expkey * static inline struct svc_expkey *
exp_get_key(svc_client *clp, dev_t dev, ino_t ino) exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
{ {
u32 fsidv[2]; u32 fsidv[3];
mk_fsid_v0(fsidv, dev, ino); if (old_valid_dev(dev)) {
return exp_find_key(clp, 0, fsidv, NULL); mk_fsid_v0(fsidv, dev, ino);
return exp_find_key(clp, 0, fsidv, NULL);
}
mk_fsid_v2(fsidv, dev, ino);
return exp_find_key(clp, 2, fsidv, NULL);
} }
/* /*
...@@ -671,11 +676,15 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) ...@@ -671,11 +676,15 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *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)
{ {
u32 fsid[2]; u32 fsid[2];
struct inode *inode; struct inode *inode = exp->ex_dentry->d_inode;
dev_t dev = inode->i_sb->s_dev;
inode = exp->ex_dentry->d_inode; if (old_valid_dev(dev)) {
mk_fsid_v0(fsid, inode->i_sb->s_dev, inode->i_ino); mk_fsid_v0(fsid, dev, inode->i_ino);
return exp_set_key(clp, 0, fsid, exp); return exp_set_key(clp, 0, fsid, exp);
}
mk_fsid_v2(fsid, dev, inode->i_ino);
return exp_set_key(clp, 2, fsid, exp);
} }
static void exp_unhash(struct svc_export *exp) static void exp_unhash(struct svc_export *exp)
...@@ -819,32 +828,42 @@ int ...@@ -819,32 +828,42 @@ int
exp_unexport(struct nfsctl_export *nxp) exp_unexport(struct nfsctl_export *nxp)
{ {
struct auth_domain *dom; struct auth_domain *dom;
svc_export *exp;
struct nameidata nd;
int err; int err;
/* Consistency check */ /* Consistency check */
if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
return -EINVAL; return -EINVAL;
exp_writelock(); exp_writelock();
err = -EINVAL; err = -EINVAL;
dom = auth_domain_find(nxp->ex_client); dom = auth_domain_find(nxp->ex_client);
if (!dom) {
if (dom) {
struct svc_expkey *key = exp_get_key(dom, nxp->ex_dev, nxp->ex_ino);
if (key && !IS_ERR(key) && key->ek_export) {
exp_do_unexport(key->ek_export);
err = 0;
expkey_put(&key->h, &svc_expkey_cache);
} else
dprintk("nfsd: no export %x/%lx for %s\n",
(unsigned)nxp->ex_dev,
(unsigned long) nxp->ex_ino, nxp->ex_client);
auth_domain_put(dom);
cache_flush();
} else
dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client); dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);
goto out_unlock;
}
err = path_lookup(nxp->ex_path, 0, &nd);
if (err)
goto out_domain;
err = -EINVAL;
exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
path_release(&nd);
if (!exp)
goto out_domain;
exp_do_unexport(exp);
exp_put(exp);
err = 0;
out_domain:
auth_domain_put(dom);
cache_flush();
out_unlock:
exp_writeunlock(); exp_writeunlock();
return err; return err;
} }
......
...@@ -186,12 +186,10 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) ...@@ -186,12 +186,10 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *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 (rqstp->rq_reffh->fh_version == 1 if (is_fsid(fhp, rqstp->rq_reffh))
&& rqstp->rq_reffh->fh_fsid_type == 1
&& (fhp->fh_export->ex_flags & NFSEXP_FSID))
p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
else else
p = xdr_encode_hyper(p, (u64) stat.dev); p = xdr_encode_hyper(p, (u64) old_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);
...@@ -222,12 +220,10 @@ encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) ...@@ -222,12 +220,10 @@ encode_saved_post_attr(struct svc_rqst *rqstp, u32 *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 (rqstp->rq_reffh->fh_version == 1 if (is_fsid(fhp, rqstp->rq_reffh))
&& rqstp->rq_reffh->fh_fsid_type == 1
&& (fhp->fh_export->ex_flags & NFSEXP_FSID))
p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
else else
p = xdr_encode_hyper(p, (u64) inode->i_sb->s_dev); p = xdr_encode_hyper(p, (u64)old_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);
......
...@@ -125,6 +125,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -125,6 +125,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
case 1: case 1:
len = 1; len = 1;
break; break;
case 2:
len = 3;
break;
default: default:
goto out; goto out;
} }
...@@ -137,7 +140,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -137,7 +140,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
if (fh->fh_size != NFS_FHSIZE) if (fh->fh_size != NFS_FHSIZE)
goto out; goto out;
/* assume old filehandle format */ /* assume old filehandle format */
xdev = u32_to_dev_t(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_v0(tfh, xdev, xino);
exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle); exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle);
...@@ -329,12 +332,21 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -329,12 +332,21 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
parent->d_name.name, dentry->d_name.name, parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0)); (inode ? inode->i_ino : 0));
if (ref_fh) { /* for large devnums rules are simple */
if (!old_valid_dev(ex_dev)) {
ref_fh_version = 1;
if (exp->ex_flags & NFSEXP_FSID)
ref_fh_fsid_type = 1;
else
ref_fh_fsid_type = 2;
} else if (ref_fh) {
ref_fh_version = ref_fh->fh_handle.fh_version; ref_fh_version = ref_fh->fh_handle.fh_version;
ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type; ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type;
if (ref_fh == fhp) if (!(exp->ex_flags & NFSEXP_FSID) || ref_fh_fsid_type == 2)
fh_put(ref_fh); ref_fh_fsid_type = 0;
} }
if (ref_fh == fhp)
fh_put(ref_fh);
if (fhp->fh_locked || fhp->fh_dentry) { if (fhp->fh_locked || fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n", printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
...@@ -353,7 +365,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -353,7 +365,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
fhp->fh_handle.fh_size = NFS_FHSIZE; fhp->fh_handle.fh_size = NFS_FHSIZE;
fhp->fh_handle.ofh_dcookie = 0xfeebbaca; fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
fhp->fh_handle.ofh_dev = htonl((MAJOR(ex_dev)<<16)| MINOR(ex_dev)); fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev);
fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_dentry->d_inode->i_ino); fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_dentry->d_inode->i_ino);
fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
...@@ -363,19 +375,33 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -363,19 +375,33 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
fhp->fh_handle.fh_version = 1; fhp->fh_handle.fh_version = 1;
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;
if ((exp->ex_flags & NFSEXP_FSID) && fhp->fh_handle.fh_fsid_type = ref_fh_fsid_type;
(ref_fh_fsid_type == 1)) { switch (ref_fh_fsid_type) {
fhp->fh_handle.fh_fsid_type = 1; case 1:
/* fsid_type 1 == 4 bytes filesystem id */ /* fsid_type 1 == 4 bytes filesystem id */
mk_fsid_v1(datap, exp->ex_fsid); mk_fsid_v1(datap, exp->ex_fsid);
datap += 1; datap += 1;
fhp->fh_handle.fh_size = 2*4; fhp->fh_handle.fh_size = 2*4;
} else { break;
fhp->fh_handle.fh_fsid_type = 0; case 2:
/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */ /*
mk_fsid_v0(datap, ex_dev, exp->ex_dentry->d_inode->i_ino); * fsid_type 2:
datap += 2; * 4byte major, 4byte minor, 4byte inode
fhp->fh_handle.fh_size = 3*4; */
mk_fsid_v2(datap, ex_dev,
exp->ex_dentry->d_inode->i_ino);
datap += 3;
fhp->fh_handle.fh_size = 4*4;
break;
default:
/*
* fsid_type 0:
* 2byte major, 2byte minor, 4byte inode
*/
mk_fsid_v0(datap, ex_dev,
exp->ex_dentry->d_inode->i_ino);
datap += 2;
fhp->fh_handle.fh_size = 3*4;
} }
if (inode) { if (inode) {
int size = fhp->fh_maxsize/4 - 3; int size = fhp->fh_maxsize/4 - 3;
......
...@@ -184,7 +184,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -184,7 +184,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
struct inode *inode; struct inode *inode;
struct dentry *dchild; struct dentry *dchild;
int nfserr, type, mode; int nfserr, type, mode;
dev_t rdev = 0; dev_t rdev = 0, wanted = old_decode_dev(attr->ia_size);
dprintk("nfsd: CREATE %s %.*s\n", dprintk("nfsd: CREATE %s %.*s\n",
SVCFH_fmt(dirfhp), argp->len, argp->name); SVCFH_fmt(dirfhp), argp->len, argp->name);
...@@ -230,7 +230,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -230,7 +230,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
inode = newfhp->fh_dentry->d_inode; inode = newfhp->fh_dentry->d_inode;
/* Unfudge the mode bits */ /* Unfudge the mode bits */
if (attr->ia_valid & ATTR_MODE) { if (attr->ia_valid & ATTR_MODE) {
type = attr->ia_mode & S_IFMT; type = attr->ia_mode & S_IFMT;
mode = attr->ia_mode & ~S_IFMT; mode = attr->ia_mode & ~S_IFMT;
if (!type) { if (!type) {
...@@ -242,7 +242,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -242,7 +242,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
case S_IFCHR: case S_IFCHR:
case S_IFBLK: case S_IFBLK:
/* reserve rdev for later checking */ /* reserve rdev for later checking */
attr->ia_size = inode->i_rdev; rdev = inode->i_rdev;
attr->ia_valid |= ATTR_SIZE; attr->ia_valid |= ATTR_SIZE;
/* FALLTHROUGH */ /* FALLTHROUGH */
...@@ -277,22 +277,21 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -277,22 +277,21 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
*/ */
if (type != S_IFREG) { if (type != S_IFREG) {
int is_borc = 0; int is_borc = 0;
u32 size = attr->ia_size;
/* may need to change when we widen dev_t */
rdev = old_decode_dev(size);
if (type != S_IFBLK && type != S_IFCHR) { if (type != S_IFBLK && type != S_IFCHR) {
rdev = 0; rdev = 0;
} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
/* If you think you've seen the worst, grok this. */ /* If you think you've seen the worst, grok this. */
type = S_IFIFO; type = S_IFIFO;
} else if (size != rdev) { } else if (!rdev && attr->ia_size != old_encode_dev(wanted)) {
/* dev got truncated because of 16bit Linux dev_t */ /* dev got truncated because of 16bit Linux dev_t */
/* may need to change when we widen dev_t */
nfserr = nfserr_inval; nfserr = nfserr_inval;
goto out_unlock; goto out_unlock;
} else { } else {
/* Okay, char or block special */ /* Okay, char or block special */
is_borc = 1; is_borc = 1;
if (!rdev)
rdev = wanted;
} }
/* we've used the SIZE information, so discard it */ /* we've used the SIZE information, so discard it */
...@@ -300,11 +299,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -300,11 +299,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
/* Make sure the type and device matches */ /* Make sure the type and device matches */
nfserr = nfserr_exist; nfserr = nfserr_exist;
if (inode && (type != (inode->i_mode & S_IFMT) || if (inode && type != (inode->i_mode & S_IFMT))
(is_borc && inode->i_rdev != rdev)))
goto out_unlock; goto out_unlock;
} }
nfserr = 0; nfserr = 0;
if (!inode) { if (!inode) {
/* File doesn't exist. Create it and set attrs */ /* File doesn't exist. Create it and set attrs */
......
...@@ -159,16 +159,14 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) ...@@ -159,16 +159,14 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
} }
*p++ = htonl((u32) stat.blksize); *p++ = htonl((u32) stat.blksize);
if (S_ISCHR(type) || S_ISBLK(type)) if (S_ISCHR(type) || S_ISBLK(type))
*p++ = htonl((u32) stat.rdev); *p++ = htonl((u32) old_encode_dev(stat.rdev));
else else
*p++ = htonl(0xffffffff); *p++ = htonl(0xffffffff);
*p++ = htonl((u32) stat.blocks); *p++ = htonl((u32) stat.blocks);
if (rqstp->rq_reffh->fh_version == 1 if (is_fsid(fhp, rqstp->rq_reffh))
&& rqstp->rq_reffh->fh_fsid_type == 1
&& (fhp->fh_export->ex_flags & NFSEXP_FSID))
*p++ = htonl((u32) fhp->fh_export->ex_fsid); *p++ = htonl((u32) fhp->fh_export->ex_fsid);
else else
*p++ = htonl((u32) stat.dev); *p++ = htonl((u32) old_encode_dev(stat.dev));
*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);
......
...@@ -65,7 +65,7 @@ struct svc_expkey { ...@@ -65,7 +65,7 @@ struct svc_expkey {
struct auth_domain * ek_client; struct auth_domain * ek_client;
int ek_fsidtype; int ek_fsidtype;
u32 ek_fsid[2]; u32 ek_fsid[3];
struct svc_export * ek_export; struct svc_export * ek_export;
}; };
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/dirent.h> #include <linux/dirent.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mount.h>
#include <linux/nfsd/debug.h> #include <linux/nfsd/debug.h>
#include <linux/nfsd/nfsfh.h> #include <linux/nfsd/nfsfh.h>
...@@ -209,6 +210,17 @@ void nfsd_lockd_shutdown(void); ...@@ -209,6 +210,17 @@ 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
......
...@@ -117,26 +117,6 @@ struct knfsd_fh { ...@@ -117,26 +117,6 @@ struct knfsd_fh {
#ifdef __KERNEL__ #ifdef __KERNEL__
/*
* Conversion macros for the filehandle fields.
*
* Keep the device numbers in "backwards compatible
* format", ie the low 16 bits contain the low 8 bits
* of the 20-bit minor and the 12-bit major number.
*
* The high 16 bits contain the rest (4 bits major
* and 12 bits minor),
*/
static inline dev_t u32_to_dev_t(__u32 udev)
{
unsigned int minor, major;
minor = (udev & 0xff) | ((udev >> 8) & 0xfff00);
major = ((udev >> 8) & 0xff) | ((udev >> 20) & 0xf00);
return MKDEV(major, minor);
}
static inline __u32 ino_t_to_u32(ino_t ino) static inline __u32 ino_t_to_u32(ino_t ino)
{ {
return (__u32) ino; return (__u32) ino;
...@@ -196,6 +176,12 @@ static inline void mk_fsid_v1(u32 *fsidv, u32 fsid) ...@@ -196,6 +176,12 @@ static inline void mk_fsid_v1(u32 *fsidv, u32 fsid)
fsidv[0] = fsid; fsidv[0] = fsid;
} }
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);
}
/* /*
* Shorthand for dprintk()'s * Shorthand for dprintk()'s
......
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