diff options
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 59 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 89 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 200 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 22 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 7 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 4 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 43 | ||||
-rw-r--r-- | include/linux/nfsd/nfsd.h | 18 | ||||
-rw-r--r-- | include/linux/nfsd/nfsfh.h | 42 | ||||
-rw-r--r-- | include/linux/nfsd/xdr4.h | 4 | ||||
-rw-r--r-- | include/linux/sunrpc/cache.h | 10 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 144 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 40 |
16 files changed, 326 insertions, 376 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 10f6e7dcf633..2d116d2298f8 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -174,9 +174,6 @@ static __be32 * encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) { - struct dentry *dentry = fhp->fh_dentry; - struct timespec time; - *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); *p++ = htonl((u32) stat->mode); *p++ = htonl((u32) stat->nlink); @@ -191,10 +188,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, *p++ = htonl((u32) MAJOR(stat->rdev)); *p++ = htonl((u32) MINOR(stat->rdev)); p = encode_fsid(p, fhp); - p = xdr_encode_hyper(p, (u64) stat->ino); + p = xdr_encode_hyper(p, stat->ino); p = encode_time3(p, &stat->atime); - lease_get_mtime(dentry->d_inode, &time); - p = encode_time3(p, &time); + p = encode_time3(p, &stat->mtime); p = encode_time3(p, &stat->ctime); return p; @@ -203,31 +199,9 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, static __be32 * encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { - struct inode *inode = fhp->fh_dentry->d_inode; - /* Attributes to follow */ *p++ = xdr_one; - - *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); - *p++ = htonl((u32) fhp->fh_post_mode); - *p++ = htonl((u32) fhp->fh_post_nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); - if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { - p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); - } else { - p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); - } - p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); - *p++ = fhp->fh_post_rdev[0]; - *p++ = fhp->fh_post_rdev[1]; - 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); - p = encode_time3(p, &fhp->fh_post_ctime); - - return p; + return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); } /* @@ -246,6 +220,7 @@ encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat); if (!err) { *p++ = xdr_one; /* attributes follow */ + lease_get_mtime(dentry->d_inode, &stat.mtime); return encode_fattr3(rqstp, p, fhp, &stat); } } @@ -284,6 +259,23 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) return encode_post_op_attr(rqstp, p, fhp); } +/* + * Fill in the post_op attr for the wcc data + */ +void fill_post_wcc(struct svc_fh *fhp) +{ + int err; + + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + + err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, + &fhp->fh_post_attr); + if (err) + fhp->fh_post_saved = 0; + else + fhp->fh_post_saved = 1; +} /* * XDR decode functions @@ -643,8 +635,11 @@ int nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { - if (resp->status == 0) + if (resp->status == 0) { + lease_get_mtime(resp->fh.fh_dentry->d_inode, + &resp->stat.mtime); p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); + } return xdr_ressize_check(rqstp, p); } @@ -802,7 +797,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p, static __be32 * encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, - int namlen, ino_t ino) + int namlen, u64 ino) { *p++ = xdr_one; /* mark entry present */ p = xdr_encode_hyper(p, ino); /* file id */ @@ -873,7 +868,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) static int encode_entry(struct readdir_cd *ccd, const char *name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type, int plus) + loff_t offset, u64 ino, unsigned int d_type, int plus) { struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, common); diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 31d6633c7fe4..9d536a8cb379 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -39,6 +39,7 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/sched.h> +#include <linux/kthread.h> #include <linux/sunrpc/xdr.h> #include <linux/sunrpc/svc.h> #include <linux/sunrpc/clnt.h> @@ -343,26 +344,28 @@ static struct rpc_version * nfs_cb_version[] = { &nfs_cb_version4, }; -/* - * Use the SETCLIENTID credential - */ -static struct rpc_cred * -nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) +/* Reference counting, callback cleanup, etc., all look racy as heck. + * And why is cb_set an atomic? */ + +static int do_probe_callback(void *data) { - struct auth_cred acred; - struct rpc_clnt *clnt = clp->cl_callback.cb_client; - struct rpc_cred *ret; - - get_group_info(clp->cl_cred.cr_group_info); - acred.uid = clp->cl_cred.cr_uid; - acred.gid = clp->cl_cred.cr_gid; - acred.group_info = clp->cl_cred.cr_group_info; - - dprintk("NFSD: looking up %s cred\n", - clnt->cl_auth->au_ops->au_name); - ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags); - put_group_info(clp->cl_cred.cr_group_info); - return ret; + struct nfs4_client *clp = data; + struct nfs4_callback *cb = &clp->cl_callback; + struct rpc_message msg = { + .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], + .rpc_argp = clp, + }; + int status; + + status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT); + + if (status) { + rpc_shutdown_client(cb->cb_client); + cb->cb_client = NULL; + } else + atomic_set(&cb->cb_set, 1); + put_nfs4_client(clp); + return 0; } /* @@ -390,11 +393,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ .flags = (RPC_CLNT_CREATE_NOPING), }; - struct rpc_message msg = { - .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], - .rpc_argp = clp, - }; - int status; + struct task_struct *t; if (atomic_read(&cb->cb_set)) return; @@ -426,16 +425,11 @@ nfsd4_probe_callback(struct nfs4_client *clp) /* the task holds a reference to the nfs4_client struct */ atomic_inc(&clp->cl_count); - msg.rpc_cred = nfsd4_lookupcred(clp,0); - if (IS_ERR(msg.rpc_cred)) - goto out_release_clp; - status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); - put_rpccred(msg.rpc_cred); + t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); - if (status != 0) { - dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n"); + if (IS_ERR(t)) goto out_release_clp; - } + return; out_release_clp: @@ -447,30 +441,6 @@ out_err: (int)clp->cl_name.len, clp->cl_name.data); } -static void -nfs4_cb_null(struct rpc_task *task, void *dummy) -{ - struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; - struct nfs4_callback *cb = &clp->cl_callback; - __be32 addr = htonl(cb->cb_addr); - - dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status); - - if (task->tk_status < 0) { - dprintk("NFSD: callback establishment to client %.*s failed\n", - (int)clp->cl_name.len, clp->cl_name.data); - goto out; - } - atomic_set(&cb->cb_set, 1); - dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr)); -out: - put_nfs4_client(clp); -} - -static const struct rpc_call_ops nfs4_cb_null_ops = { - .rpc_call_done = nfs4_cb_null, -}; - /* * called with dp->dl_count inc'ed. * nfs4_lock_state() may or may not have been called. @@ -491,10 +461,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt) return; - msg.rpc_cred = nfsd4_lookupcred(clp, 0); - if (IS_ERR(msg.rpc_cred)) - goto out; - cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ cbr->cbr_dp = dp; @@ -515,13 +481,12 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); } out_put_cred: - put_rpccred(msg.rpc_cred); -out: if (status == -EIO) atomic_set(&clp->cl_callback.cb_set, 0); /* Success or failure, now we're either waiting for lease expiration * or deleg_return. */ dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count)); + put_nfs4_client(clp); nfs4_put_delegation(dp); return; } diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 2ccffde81b84..4c0c683ce07a 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -207,6 +207,7 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) { struct ent ent, *res; char *buf1, *bp; + int len; int error = -EINVAL; if (buf[buflen - 1] != '\n') @@ -248,10 +249,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) goto out; /* Name */ - error = qword_get(&buf, buf1, PAGE_SIZE); - if (error == -EINVAL) + error = -EINVAL; + len = qword_get(&buf, buf1, PAGE_SIZE); + if (len < 0) goto out; - if (error == -ENOENT) + if (len == 0) set_bit(CACHE_NEGATIVE, &ent.h.flags); else { if (error >= IDMAP_NAMESZ) { diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 29b7e63cb32c..18ead1790bb3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -238,12 +238,12 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_DELEGATE_PREV: open->op_stateowner->so_confirmed = 1; - printk("NFSD: unsupported OPEN claim type %d\n", + dprintk("NFSD: unsupported OPEN claim type %d\n", open->op_claim_type); status = nfserr_notsupp; goto out; default: - printk("NFSD: Invalid OPEN claim type %d\n", + dprintk("NFSD: Invalid OPEN claim type %d\n", open->op_claim_type); status = nfserr_inval; goto out; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3f559700788f..6f182d25793d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -358,9 +358,22 @@ alloc_client(struct xdr_netobj name) return clp; } +static void +shutdown_callback_client(struct nfs4_client *clp) +{ + struct rpc_clnt *clnt = clp->cl_callback.cb_client; + + /* shutdown rpc client, ending any outstanding recall rpcs */ + if (clnt) { + clp->cl_callback.cb_client = NULL; + rpc_shutdown_client(clnt); + } +} + static inline void free_client(struct nfs4_client *clp) { + shutdown_callback_client(clp); if (clp->cl_cred.cr_group_info) put_group_info(clp->cl_cred.cr_group_info); kfree(clp->cl_name.data); @@ -375,18 +388,6 @@ put_nfs4_client(struct nfs4_client *clp) } static void -shutdown_callback_client(struct nfs4_client *clp) -{ - struct rpc_clnt *clnt = clp->cl_callback.cb_client; - - /* shutdown rpc client, ending any outstanding recall rpcs */ - if (clnt) { - clp->cl_callback.cb_client = NULL; - rpc_shutdown_client(clnt); - } -} - -static void expire_client(struct nfs4_client *clp) { struct nfs4_stateowner *sop; @@ -396,8 +397,6 @@ expire_client(struct nfs4_client *clp) dprintk("NFSD: expire_client cl_count %d\n", atomic_read(&clp->cl_count)); - shutdown_callback_client(clp); - INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); while (!list_empty(&clp->cl_delegations)) { @@ -462,26 +461,28 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) { } static inline int -same_name(const char *n1, const char *n2) { +same_name(const char *n1, const char *n2) +{ return 0 == memcmp(n1, n2, HEXDIR_LEN); } static int -cmp_verf(nfs4_verifier *v1, nfs4_verifier *v2) { - return(!memcmp(v1->data,v2->data,sizeof(v1->data))); +same_verf(nfs4_verifier *v1, nfs4_verifier *v2) +{ + return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); } static int -cmp_clid(clientid_t * cl1, clientid_t * cl2) { - return((cl1->cl_boot == cl2->cl_boot) && - (cl1->cl_id == cl2->cl_id)); +same_clid(clientid_t *cl1, clientid_t *cl2) +{ + return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); } /* XXX what about NGROUP */ static int -cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){ - return(cr1->cr_uid == cr2->cr_uid); - +same_creds(struct svc_cred *cr1, struct svc_cred *cr2) +{ + return cr1->cr_uid == cr2->cr_uid; } static void @@ -507,7 +508,7 @@ check_name(struct xdr_netobj name) { if (name.len == 0) return 0; if (name.len > NFS4_OPAQUE_LIMIT) { - printk("NFSD: check_name: name too long(%d)!\n", name.len); + dprintk("NFSD: check_name: name too long(%d)!\n", name.len); return 0; } return 1; @@ -546,7 +547,7 @@ find_confirmed_client(clientid_t *clid) unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { - if (cmp_clid(&clp->cl_clientid, clid)) + if (same_clid(&clp->cl_clientid, clid)) return clp; } return NULL; @@ -559,7 +560,7 @@ find_unconfirmed_client(clientid_t *clid) unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { - if (cmp_clid(&clp->cl_clientid, clid)) + if (same_clid(&clp->cl_clientid, clid)) return clp; } return NULL; @@ -753,7 +754,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * or different ip_address */ status = nfserr_clid_inuse; - if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred) + if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) || conf->cl_addr != sin->sin_addr.s_addr) { dprintk("NFSD: setclientid: string in use by client" "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr)); @@ -772,14 +773,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new, &clverifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new, strhashval); - } else if (cmp_verf(&conf->cl_verifier, &clverifier)) { + } else if (same_verf(&conf->cl_verifier, &clverifier)) { /* * CASE 1: * cl_name match, confirmed, principal match @@ -804,13 +799,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new,&conf->cl_verifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); copy_clid(new, conf); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new,strhashval); } else if (!unconf) { /* * CASE 2: @@ -823,14 +812,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new,&clverifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new, strhashval); - } else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) { + } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) { /* * CASE3: * confirmed found (name, principal match) @@ -850,19 +833,19 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, dname); if (new == NULL) goto out; - copy_verf(new,&clverifier); - new->cl_addr = sin->sin_addr.s_addr; - copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); - gen_confirm(new); - gen_callback(new, setclid); - add_to_unconfirmed(new, strhashval); } else { /* No cases hit !!! */ status = nfserr_inval; goto out; } + copy_verf(new, &clverifier); + new->cl_addr = sin->sin_addr.s_addr; + copy_cred(&new->cl_cred, &rqstp->rq_cred); + gen_confirm(new); + gen_callback(new, setclid); + add_to_unconfirmed(new, strhashval); setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; setclid->se_clientid.cl_id = new->cl_clientid.cl_id; memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); @@ -910,16 +893,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, goto out; if ((conf && unconf) && - (cmp_verf(&unconf->cl_confirm, &confirm)) && - (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && + (same_verf(&unconf->cl_confirm, &confirm)) && + (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) && (same_name(conf->cl_recdir,unconf->cl_recdir)) && - (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { + (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) { /* CASE 1: * unconf record that matches input clientid and input confirm. * conf record that matches input clientid. * conf and unconf records match names, verifiers */ - if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) + if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) status = nfserr_clid_inuse; else { /* XXX: We just turn off callbacks until we can handle @@ -933,7 +916,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, } } else if ((conf && !unconf) || ((conf && unconf) && - (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || + (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) || !same_name(conf->cl_recdir, unconf->cl_recdir)))) { /* CASE 2: * conf record that matches input clientid. @@ -941,18 +924,18 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, * unconf->cl_name or unconf->cl_verifier don't match the * conf record. */ - if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) + if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) status = nfserr_clid_inuse; else status = nfs_ok; } else if (!conf && unconf - && cmp_verf(&unconf->cl_confirm, &confirm)) { + && same_verf(&unconf->cl_confirm, &confirm)) { /* CASE 3: * conf record not found. * unconf record found. * unconf->cl_confirm matches input confirm */ - if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { + if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { status = nfserr_clid_inuse; } else { unsigned int hash = @@ -967,8 +950,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, conf = unconf; status = nfs_ok; } - } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) - && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, + } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) + && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, &confirm)))) { /* CASE 4: * conf record not found, or if conf, conf->cl_confirm does not @@ -1019,7 +1002,7 @@ nfsd4_free_slab(struct kmem_cache **slab) *slab = NULL; } -static void +void nfsd4_free_slabs(void) { nfsd4_free_slab(&stateowner_slab); @@ -1207,10 +1190,12 @@ move_to_close_lru(struct nfs4_stateowner *sop) } static int -cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { - return ((sop->so_owner.len == owner->len) && - !memcmp(sop->so_owner.data, owner->data, owner->len) && - (sop->so_client->cl_clientid.cl_id == clid->cl_id)); +same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, + clientid_t *clid) +{ + return (sop->so_owner.len == owner->len) && + 0 == memcmp(sop->so_owner.data, owner->data, owner->len) && + (sop->so_client->cl_clientid.cl_id == clid->cl_id); } static struct nfs4_stateowner * @@ -1219,7 +1204,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) struct nfs4_stateowner *so = NULL; list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { - if (cmp_owner_str(so, &open->op_owner, &open->op_clientid)) + if (same_owner_str(so, &open->op_owner, &open->op_clientid)) return so; } return NULL; @@ -1360,6 +1345,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl) * lock) we know the server hasn't removed the lease yet, we know * it's safe to take a reference: */ atomic_inc(&dp->dl_count); + atomic_inc(&dp->dl_client->cl_count); spin_lock(&recall_lock); list_add_tail(&dp->dl_recall_lru, &del_recall_lru); @@ -1368,8 +1354,12 @@ void nfsd_break_deleg_cb(struct file_lock *fl) /* only place dl_time is set. protected by lock_kernel*/ dp->dl_time = get_seconds(); - /* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */ - fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ; + /* + * We don't want the locks code to timeout the lease for us; + * we'll remove it ourself if the delegation isn't returned + * in time. + */ + fl->fl_break_time = 0; t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); if (IS_ERR(t)) { @@ -1378,6 +1368,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl) printk(KERN_INFO "NFSD: Callback thread failed for " "for client (clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); + put_nfs4_client(dp->dl_client); nfs4_put_delegation(dp); } } @@ -1738,7 +1729,7 @@ out: if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && flag == NFS4_OPEN_DELEGATE_NONE && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) - printk("NFSD: WARNING: refusing delegation reclaim\n"); + dprintk("NFSD: WARNING: refusing delegation reclaim\n"); open->op_delegate_type = flag; } @@ -2147,7 +2138,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei *sopp = NULL; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { - printk("NFSD: preprocess_seqid_op: magic stateid!\n"); + dprintk("NFSD: preprocess_seqid_op: magic stateid!\n"); return nfserr_bad_stateid; } @@ -2181,25 +2172,24 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei lkflg = setlkflg(lock->lk_type); if (lock->lk_is_new) { - if (!sop->so_is_open_owner) - return nfserr_bad_stateid; - if (!cmp_clid(&clp->cl_clientid, lockclid)) + if (!sop->so_is_open_owner) + return nfserr_bad_stateid; + if (!same_clid(&clp->cl_clientid, lockclid)) return nfserr_bad_stateid; - /* stp is the open stateid */ - status = nfs4_check_openmode(stp, lkflg); - if (status) - return status; - } else { - /* stp is the lock stateid */ - status = nfs4_check_openmode(stp->st_openstp, lkflg); - if (status) - return status; + /* stp is the open stateid */ + status = nfs4_check_openmode(stp, lkflg); + if (status) + return status; + } else { + /* stp is the lock stateid */ + status = nfs4_check_openmode(stp->st_openstp, lkflg); + if (status) + return status; } - } if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { - printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); + dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); return nfserr_bad_stateid; } @@ -2215,22 +2205,22 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei goto check_replay; if (sop->so_confirmed && flags & CONFIRM) { - printk("NFSD: preprocess_seqid_op: expected" + dprintk("NFSD: preprocess_seqid_op: expected" " unconfirmed stateowner!\n"); return nfserr_bad_stateid; } if (!sop->so_confirmed && !(flags & CONFIRM)) { - printk("NFSD: preprocess_seqid_op: stateowner not" + dprintk("NFSD: preprocess_seqid_op: stateowner not" " confirmed yet!\n"); return nfserr_bad_stateid; } if (stateid->si_generation > stp->st_stateid.si_generation) { - printk("NFSD: preprocess_seqid_op: future stateid?!\n"); + dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); return nfserr_bad_stateid; } if (stateid->si_generation < stp->st_stateid.si_generation) { - printk("NFSD: preprocess_seqid_op: old stateid!\n"); + dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); return nfserr_old_stateid; } renew_client(sop->so_client); @@ -2242,7 +2232,7 @@ check_replay: /* indicate replay to calling function */ return nfserr_replay_me; } - printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", + dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", sop->so_seqid, seqid); *sopp = NULL; return nfserr_bad_seqid; @@ -2561,7 +2551,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, struct nfs4_stateowner *op; list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { - if (cmp_owner_str(op, owner, clid)) + if (same_owner_str(op, owner, clid)) return op; } return NULL; @@ -2855,7 +2845,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, file_lock.fl_type = F_WRLCK; break; default: - printk("NFSD: nfs4_lockt: bad lock type!\n"); + dprintk("NFSD: nfs4_lockt: bad lock type!\n"); status = nfserr_inval; goto out; } @@ -3025,7 +3015,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, INIT_LIST_HEAD(&matches); for (i = 0; i < LOCK_HASH_SIZE; i++) { list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { - if (!cmp_owner_str(sop, owner, clid)) + if (!same_owner_str(sop, owner, clid)) continue; list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { @@ -3149,11 +3139,14 @@ nfs4_check_open_reclaim(clientid_t *clid) /* initialization to perform at module load time: */ -void +int nfs4_state_init(void) { - int i; + int i, status; + status = nfsd4_init_slabs(); + if (status) + return status; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&conf_str_hashtbl[i]); @@ -3182,6 +3175,7 @@ nfs4_state_init(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); reclaim_str_hashtbl_size = 0; + return 0; } static void @@ -3242,20 +3236,15 @@ __nfs4_state_start(void) set_max_delegations(); } -int +void nfs4_state_start(void) { - int status; - if (nfs4_init) - return 0; - status = nfsd4_init_slabs(); - if (status) - return status; + return; nfsd4_load_reboot_recovery_data(); __nfs4_state_start(); nfs4_init = 1; - return 0; + return; } int @@ -3313,7 +3302,6 @@ nfs4_state_shutdown(void) nfs4_lock_state(); nfs4_release_reclaim(); __nfs4_state_shutdown(); - nfsd4_free_slabs(); nfs4_unlock_state(); } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8ef0964179bc..e15f2cf8ac15 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1475,7 +1475,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, err = vfs_getattr(exp->ex_mnt, dentry, &stat); if (err) goto out_nfserr; - if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) || + if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | + FATTR4_WORD0_MAXNAME)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { err = vfs_statfs(dentry, &statfs); @@ -1679,7 +1680,7 @@ out_acl: if (bmval0 & FATTR4_WORD0_FILEID) { if ((buflen -= 8) < 0) goto out_resource; - WRITE64((u64) stat.ino); + WRITE64(stat.ino); } if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { if ((buflen -= 8) < 0) @@ -1721,7 +1722,7 @@ out_acl: if (bmval0 & FATTR4_WORD0_MAXNAME) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(~(u32) 0); + WRITE32(statfs.f_namelen); } if (bmval0 & FATTR4_WORD0_MAXREAD) { if ((buflen -= 8) < 0) @@ -1821,16 +1822,15 @@ out_acl: WRITE32(stat.mtime.tv_nsec); } if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { - struct dentry *mnt_pnt, *mnt_root; - if ((buflen -= 8) < 0) goto out_resource; - mnt_root = exp->ex_mnt->mnt_root; - if (mnt_root->d_inode == dentry->d_inode) { - mnt_pnt = exp->ex_mnt->mnt_mountpoint; - WRITE64((u64) mnt_pnt->d_inode->i_ino); - } else - WRITE64((u64) stat.ino); + if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { + err = vfs_getattr(exp->ex_mnt->mnt_parent, + exp->ex_mnt->mnt_mountpoint, &stat); + if (err) + goto out_nfserr; + } + WRITE64(stat.ino); } *attrlenp = htonl((char *)p - (char *)attrlenp - 4); *countp = p - buffer; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index baac89d917ca..77dc9893b7ba 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -298,7 +298,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) * qword quoting is used, so filehandle will be \x.... */ char *dname, *path; - int maxsize; + int uninitialized_var(maxsize); char *mesg = buf; int len; struct auth_domain *dom; @@ -679,11 +679,13 @@ static int __init init_nfsd(void) int retval; printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); + retval = nfs4_state_init(); /* nfs4 locking state */ + if (retval) + return retval; nfsd_stat_init(); /* Statistics */ nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ nfsd_lockd_init(); /* lockd->nfsd callbacks */ - nfs4_state_init(); /* NFSv4 locking state */ nfsd_idmap_init(); /* Name to ID mapping */ if (proc_mkdir("fs/nfs", NULL)) { struct proc_dir_entry *entry; @@ -712,6 +714,7 @@ static void __exit exit_nfsd(void) nfsd_stat_shutdown(); nfsd_lockd_shutdown(); nfsd_idmap_shutdown(); + nfsd4_free_slabs(); unregister_filesystem(&nfsd_fs_type); } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index a8c89ae4c743..1190aeaa92be 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -349,9 +349,7 @@ nfsd_svc(unsigned short port, int nrservs) error = nfsd_racache_init(2*nrservs); if (error<0) goto out; - error = nfs4_state_start(); - if (error<0) - goto out; + nfs4_state_start(); nfsd_reset_versions(); @@ -546,10 +544,8 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) /* Now call the procedure handler, and encode NFS status. */ nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); nfserr = map_new_errors(rqstp->rq_vers, nfserr); - if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) - nfserr = nfserr_dropit; if (nfserr == nfserr_dropit) { - dprintk("nfsd: Dropping request due to malloc failure!\n"); + dprintk("nfsd: Dropping request; may be revisited later\n"); nfsd_cache_update(rqstp, RC_NOCACHE, NULL); return 0; } diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index cb3e7fadb772..986f9b32083c 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -523,6 +523,10 @@ nfssvc_encode_entry(void *ccdv, const char *name, cd->common.err = nfserr_toosmall; return -EINVAL; } + if (ino > ~((u32) 0)) { + cd->common.err = nfserr_fbig; + return -EINVAL; + } *p++ = xdr_one; /* mark entry present */ *p++ = htonl((u32) ino); /* file id */ p = xdr_encode_array(p, name, namlen);/* name length & name */ diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7867151ebb83..cec78c82b1f9 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -295,7 +295,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (!iap->ia_valid) goto out; - /* NFSv2 does not differentiate between "set-[ac]time-to-now" + /* + * NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which * requires ownership. * So if it looks like it might be "set both to the same time which @@ -308,25 +309,33 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, */ #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) #define MAX_TOUCH_TIME_ERROR (30*60) - if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET - && iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec - ) { - /* Looks probable. Now just make sure time is in the right ballpark. - * Solaris, at least, doesn't seem to care what the time request is. - * We require it be within 30 minutes of now. - */ - time_t delta = iap->ia_atime.tv_sec - get_seconds(); - if (delta<0) delta = -delta; - if (delta < MAX_TOUCH_TIME_ERROR && - inode_change_ok(inode, iap) != 0) { - /* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME - * this will cause notify_change to set these times to "now" + if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && + iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { + /* + * Looks probable. + * + * Now just make sure time is in the right ballpark. + * Solaris, at least, doesn't seem to care what the time + * request is. We require it be within 30 minutes of now. */ - iap->ia_valid &= ~BOTH_TIME_SET; - } + time_t delta = iap->ia_atime.tv_sec - get_seconds(); + if (delta < 0) + delta = -delta; + if (delta < MAX_TOUCH_TIME_ERROR && + inode_change_ok(inode, iap) != 0) { + /* + * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. + * This will cause notify_change to set these times + * to "now" + */ + iap->ia_valid &= ~BOTH_TIME_SET; + } } - /* The size case is special. It changes the file as well as the attributes. */ + /* + * The size case is special. + * It changes the file as well as the attributes. + */ if (iap->ia_valid & ATTR_SIZE) { if (iap->ia_size < inode->i_size) { err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index e452256d3f72..604a0d786bc6 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -153,19 +153,21 @@ extern int nfsd_max_blksize; */ #ifdef CONFIG_NFSD_V4 extern unsigned int max_delegations; -void nfs4_state_init(void); -int nfs4_state_start(void); +int nfs4_state_init(void); +void nfsd4_free_slabs(void); +void nfs4_state_start(void); void nfs4_state_shutdown(void); time_t nfs4_lease_time(void); void nfs4_reset_lease(time_t leasetime); int nfs4_reset_recoverydir(char *recdir); #else -static inline void nfs4_state_init(void){}; -static inline int nfs4_state_start(void){return 0;} -static inline void nfs4_state_shutdown(void){} -static inline time_t nfs4_lease_time(void){return 0;} -static inline void nfs4_reset_lease(time_t leasetime){} -static inline int nfs4_reset_recoverydir(char *recdir) {return 0;} +static inline int nfs4_state_init(void) { return 0; } +static inline void nfsd4_free_slabs(void) { } +static inline void nfs4_state_start(void) { } +static inline void nfs4_state_shutdown(void) { } +static inline time_t nfs4_lease_time(void) { return 0; } +static inline void nfs4_reset_lease(time_t leasetime) { } +static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } #endif /* diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 11e568ee0eeb..d1941cb965e9 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -150,17 +150,7 @@ typedef struct svc_fh { struct timespec fh_pre_ctime; /* ctime before oper */ /* Post-op attributes saved in fh_unlock */ - umode_t fh_post_mode; /* i_mode */ - nlink_t fh_post_nlink; /* i_nlink */ - uid_t fh_post_uid; /* i_uid */ - gid_t fh_post_gid; /* i_gid */ - __u64 fh_post_size; /* i_size */ - unsigned long fh_post_blocks; /* i_blocks */ - unsigned long fh_post_blksize;/* i_blksize */ - __be32 fh_post_rdev[2];/* i_rdev */ - struct timespec fh_post_atime; /* i_atime */ - struct timespec fh_post_mtime; /* i_mtime */ - struct timespec fh_post_ctime; /* i_ctime */ + struct kstat fh_post_attr; /* full attrs after operation */ #endif /* CONFIG_NFSD_V3 */ } svc_fh; @@ -297,36 +287,12 @@ fill_pre_wcc(struct svc_fh *fhp) if (!fhp->fh_pre_saved) { fhp->fh_pre_mtime = inode->i_mtime; fhp->fh_pre_ctime = inode->i_ctime; - fhp->fh_pre_size = inode->i_size; - fhp->fh_pre_saved = 1; + fhp->fh_pre_size = inode->i_size; + fhp->fh_pre_saved = 1; } } -/* - * Fill in the post_op attr for the wcc data - */ -static inline void -fill_post_wcc(struct svc_fh *fhp) -{ - struct inode *inode = fhp->fh_dentry->d_inode; - - if (fhp->fh_post_saved) - printk("nfsd: inode locked twice during operation.\n"); - - fhp->fh_post_mode = inode->i_mode; - fhp->fh_post_nlink = inode->i_nlink; - fhp->fh_post_uid = inode->i_uid; - fhp->fh_post_gid = inode->i_gid; - fhp->fh_post_size = inode->i_size; - fhp->fh_post_blksize = BLOCK_SIZE; - fhp->fh_post_blocks = inode->i_blocks; - fhp->fh_post_rdev[0] = htonl((u32)imajor(inode)); - fhp->fh_post_rdev[1] = htonl((u32)iminor(inode)); - fhp->fh_post_atime = inode->i_atime; - fhp->fh_post_mtime = inode->i_mtime; - fhp->fh_post_ctime = inode->i_ctime; - fhp->fh_post_saved = 1; -} +extern void fill_post_wcc(struct svc_fh *); #else #define fill_pre_wcc(ignored) #define fill_post_wcc(notused) diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 1b653267133a..b0ddfb41c790 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -428,8 +428,8 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) cinfo->atomic = 1; cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; - cinfo->after_ctime_sec = fhp->fh_post_ctime.tv_sec; - cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec; + cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; + cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; } int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 3699dff7db8f..bd7a6b0a87af 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -136,16 +136,6 @@ sunrpc_cache_update(struct cache_detail *detail, struct cache_head *new, struct cache_head *old, int hash); -#define cache_for_each(pos, detail, index, member) \ - for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ; \ - ({if (index==0)read_unlock(&(detail)->hash_lock); index--;}); \ - ) \ - for (pos = container_of((detail)->hash_table[index], typeof(*pos), member); \ - &pos->member; \ - pos = container_of(pos->member.next, typeof(*pos), member)) - - - extern void cache_clean_deferred(void *owner); static inline struct cache_head *cache_get(struct cache_head *h) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 7da7050f06c3..73940df6c460 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -631,7 +631,8 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o) return 0; } -/* Verify the checksum on the header and return SVC_OK on success. +/* + * Verify the checksum on the header and return SVC_OK on success. * Otherwise, return SVC_DROP (in the case of a bad sequence number) * or return SVC_DENIED and indicate error in authp. */ @@ -961,6 +962,78 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip) } /* + * Having read the cred already and found we're in the context + * initiation case, read the verifier and initiate (or check the results + * of) upcalls to userspace for help with context initiation. If + * the upcall results are available, write the verifier and result. + * Otherwise, drop the request pending an answer to the upcall. + */ +static int svcauth_gss_handle_init(struct svc_rqst *rqstp, + struct rpc_gss_wire_cred *gc, __be32 *authp) +{ + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; + struct xdr_netobj tmpobj; + struct rsi *rsip, rsikey; + + /* Read the verifier; should be NULL: */ + *authp = rpc_autherr_badverf; + if (argv->iov_len < 2 * 4) + return SVC_DENIED; + if (svc_getnl(argv) != RPC_AUTH_NULL) + return SVC_DENIED; + if (svc_getnl(argv) != 0) + return SVC_DENIED; + + /* Martial context handle and token for upcall: */ + *authp = rpc_autherr_badcred; + if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0) + return SVC_DENIED; + memset(&rsikey, 0, sizeof(rsikey)); + if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx)) + return SVC_DROP; + *authp = rpc_autherr_badverf; + if (svc_safe_getnetobj(argv, &tmpobj)) { + kfree(rsikey.in_handle.data); + return SVC_DENIED; + } + if (dup_netobj(&rsikey.in_token, &tmpobj)) { + kfree(rsikey.in_handle.data); + return SVC_DROP; + } + + /* Perform upcall, or find upcall result: */ + rsip = rsi_lookup(&rsikey); + rsi_free(&rsikey); + if (!rsip) + return SVC_DROP; + switch (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) { + case -EAGAIN: + case -ETIMEDOUT: + case -ENOENT: + /* No upcall result: */ + return SVC_DROP; + case 0: + /* Got an answer to the upcall; use it: */ + if (gss_write_init_verf(rqstp, rsip)) + return SVC_DROP; + if (resv->iov_len + 4 > PAGE_SIZE) + return SVC_DROP; + svc_putnl(resv, RPC_SUCCESS); + if (svc_safe_putnetobj(resv, &rsip->out_handle)) + return SVC_DROP; + if (resv->iov_len + 3 * 4 > PAGE_SIZE) + return SVC_DROP; + svc_putnl(resv, rsip->major_status); + svc_putnl(resv, rsip->minor_status); + svc_putnl(resv, GSS_SEQ_WIN); + if (svc_safe_putnetobj(resv, &rsip->out_token)) + return SVC_DROP; + } + return SVC_COMPLETE; +} + +/* * Accept an rpcsec packet. * If context establishment, punt to user space * If data exchange, verify/decrypt @@ -974,11 +1047,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; u32 crlen; - struct xdr_netobj tmpobj; struct gss_svc_data *svcdata = rqstp->rq_auth_data; struct rpc_gss_wire_cred *gc; struct rsc *rsci = NULL; - struct rsi *rsip, rsikey; __be32 *rpcstart; __be32 *reject_stat = resv->iov_base + resv->iov_len; int ret; @@ -1023,30 +1094,14 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0)) goto auth_err; - /* - * We've successfully parsed the credential. Let's check out the - * verifier. An AUTH_NULL verifier is allowed (and required) for - * INIT and CONTINUE_INIT requests. AUTH_RPCSEC_GSS is required for - * PROC_DATA and PROC_DESTROY. - * - * AUTH_NULL verifier is 0 (AUTH_NULL), 0 (length). - * AUTH_RPCSEC_GSS verifier is: - * 6 (AUTH_RPCSEC_GSS), length, checksum. - * checksum is calculated over rpcheader from xid up to here. - */ *authp = rpc_autherr_badverf; switch (gc->gc_proc) { case RPC_GSS_PROC_INIT: case RPC_GSS_PROC_CONTINUE_INIT: - if (argv->iov_len < 2 * 4) - goto auth_err; - if (svc_getnl(argv) != RPC_AUTH_NULL) - goto auth_err; - if (svc_getnl(argv) != 0) - goto auth_err; - break; + return svcauth_gss_handle_init(rqstp, gc, authp); case RPC_GSS_PROC_DATA: case RPC_GSS_PROC_DESTROY: + /* Look up the context, and check the verifier: */ *authp = rpcsec_gsserr_credproblem; rsci = gss_svc_searchbyctx(&gc->gc_ctx); if (!rsci) @@ -1067,51 +1122,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) /* now act upon the command: */ switch (gc->gc_proc) { - case RPC_GSS_PROC_INIT: - case RPC_GSS_PROC_CONTINUE_INIT: - *authp = rpc_autherr_badcred; - if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0) - goto auth_err; - memset(&rsikey, 0, sizeof(rsikey)); - if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx)) - goto drop; - *authp = rpc_autherr_badverf; - if (svc_safe_getnetobj(argv, &tmpobj)) { - kfree(rsikey.in_handle.data); - goto auth_err; - } - if (dup_netobj(&rsikey.in_token, &tmpobj)) { - kfree(rsikey.in_handle.data); - goto drop; - } - - rsip = rsi_lookup(&rsikey); - rsi_free(&rsikey); - if (!rsip) { - goto drop; - } - switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) { - case -EAGAIN: - case -ETIMEDOUT: - case -ENOENT: - goto drop; - case 0: - if (gss_write_init_verf(rqstp, rsip)) - goto drop; - if (resv->iov_len + 4 > PAGE_SIZE) - goto drop; - svc_putnl(resv, RPC_SUCCESS); - if (svc_safe_putnetobj(resv, &rsip->out_handle)) - goto drop; - if (resv->iov_len + 3 * 4 > PAGE_SIZE) - goto drop; - svc_putnl(resv, rsip->major_status); - svc_putnl(resv, rsip->minor_status); - svc_putnl(resv, GSS_SEQ_WIN); - if (svc_safe_putnetobj(resv, &rsip->out_token)) - goto drop; - } - goto complete; case RPC_GSS_PROC_DESTROY: if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq)) goto auth_err; @@ -1158,7 +1168,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) goto out; } auth_err: - /* Restore write pointer to original value: */ + /* Restore write pointer to its original value: */ xdr_ressize_check(rqstp, reject_stat); ret = SVC_DENIED; goto out; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 55ea6df069de..a4a6bf7deaa4 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -777,6 +777,30 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) } /* + * Printk the given error with the address of the client that caused it. + */ +static int +__attribute__ ((format (printf, 2, 3))) +svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) +{ + va_list args; + int r; + char buf[RPC_MAX_ADDRBUFLEN]; + + if (!net_ratelimit()) + return 0; + + printk(KERN_WARNING "svc: %s: ", + svc_print_addr(rqstp, buf, sizeof(buf))); + + va_start(args, fmt); + r = vprintk(fmt, args); + va_end(args); + + return r; +} + +/* * Process the RPC request. */ int @@ -963,14 +987,13 @@ svc_process(struct svc_rqst *rqstp) return 0; err_short_len: - if (net_ratelimit()) - printk("svc: short len %Zd, dropping request\n", argv->iov_len); + svc_printk(rqstp, "short len %Zd, dropping request\n", + argv->iov_len); goto dropit; /* drop request */ err_bad_dir: - if (net_ratelimit()) - printk("svc: bad direction %d, dropping request\n", dir); + svc_printk(rqstp, "bad direction %d, dropping request\n", dir); serv->sv_stats->rpcbadfmt++; goto dropit; /* drop request */ @@ -1000,8 +1023,7 @@ err_bad_prog: goto sendit; err_bad_vers: - if (net_ratelimit()) - printk("svc: unknown version (%d for prog %d, %s)\n", + svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n", vers, prog, progp->pg_name); serv->sv_stats->rpcbadfmt++; @@ -1011,16 +1033,14 @@ err_bad_vers: goto sendit; err_bad_proc: - if (net_ratelimit()) - printk("svc: unknown procedure (%d)\n", proc); + svc_printk(rqstp, "unknown procedure (%d)\n", proc); serv->sv_stats->rpcbadfmt++; svc_putnl(resv, RPC_PROC_UNAVAIL); goto sendit; err_garbage: - if (net_ratelimit()) - printk("svc: failed to decode args\n"); + svc_printk(rqstp, "failed to decode args\n"); rpc_stat = rpc_garbage_args; err_bad: |