Commit 0b233b7c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-3.19' of git://linux-nfs.org/~bfields/linux

Pull nfsd updates from Bruce Fields:
 "A comparatively quieter cycle for nfsd this time, but still with two
  larger changes:

   - RPC server scalability improvements from Jeff Layton (using RCU
     instead of a spinlock to find idle threads).

   - server-side NFSv4.2 ALLOCATE/DEALLOCATE support from Anna
     Schumaker, enabling fallocate on new clients"

* 'for-3.19' of git://linux-nfs.org/~bfields/linux: (32 commits)
  nfsd4: fix xdr4 count of server in fs_location4
  nfsd4: fix xdr4 inclusion of escaped char
  sunrpc/cache: convert to use string_escape_str()
  sunrpc: only call test_bit once in svc_xprt_received
  fs: nfsd: Fix signedness bug in compare_blob
  sunrpc: add some tracepoints around enqueue and dequeue of svc_xprt
  sunrpc: convert to lockless lookup of queued server threads
  sunrpc: fix potential races in pool_stats collection
  sunrpc: add a rcu_head to svc_rqst and use kfree_rcu to free it
  sunrpc: require svc_create callers to pass in meaningful shutdown routine
  sunrpc: have svc_wake_up only deal with pool 0
  sunrpc: convert sp_task_pending flag to use atomic bitops
  sunrpc: move rq_cachetype field to better optimize space
  sunrpc: move rq_splice_ok flag into rq_flags
  sunrpc: move rq_dropme flag into rq_flags
  sunrpc: move rq_usedeferral flag to rq_flags
  sunrpc: move rq_local field to rq_flags
  sunrpc: add a generic rq_flags field to svc_rqst and move rq_secure to it
  nfsd: minor off by one checks in __write_versions()
  sunrpc: release svc_pool_map reference when serv allocation fails
  ...
parents 6f51ee70 bf7491f1
...@@ -446,7 +446,7 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) ...@@ -446,7 +446,7 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
loff_t start = range->pgstart * PAGE_SIZE; loff_t start = range->pgstart * PAGE_SIZE;
loff_t end = (range->pgend + 1) * PAGE_SIZE; loff_t end = (range->pgend + 1) * PAGE_SIZE;
do_fallocate(range->asma->file, vfs_fallocate(range->asma->file,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
start, end - start); start, end - start);
range->purged = ASHMEM_WAS_PURGED; range->purged = ASHMEM_WAS_PURGED;
......
...@@ -443,7 +443,7 @@ int ioctl_preallocate(struct file *filp, void __user *argp) ...@@ -443,7 +443,7 @@ int ioctl_preallocate(struct file *filp, void __user *argp)
return -EINVAL; return -EINVAL;
} }
return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
} }
static int file_ioctl(struct file *filp, unsigned int cmd, static int file_ioctl(struct file *filp, unsigned int cmd,
......
...@@ -214,7 +214,7 @@ int nsm_monitor(const struct nlm_host *host) ...@@ -214,7 +214,7 @@ int nsm_monitor(const struct nlm_host *host)
if (unlikely(res.status != 0)) if (unlikely(res.status != 0))
status = -EIO; status = -EIO;
if (unlikely(status < 0)) { if (unlikely(status < 0)) {
printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); pr_notice_ratelimited("lockd: cannot monitor %s\n", nsm->sm_name);
return status; return status;
} }
......
...@@ -350,7 +350,7 @@ static struct svc_serv *lockd_create_svc(void) ...@@ -350,7 +350,7 @@ static struct svc_serv *lockd_create_svc(void)
printk(KERN_WARNING printk(KERN_WARNING
"lockd_up: no pid, %d users??\n", nlmsvc_users); "lockd_up: no pid, %d users??\n", nlmsvc_users);
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL); serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, svc_rpcb_cleanup);
if (!serv) { if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n"); printk(KERN_WARNING "lockd_up: create service failed\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <linux/file.h> #include <linux/file.h>
#include <linux/falloc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "idmap.h" #include "idmap.h"
...@@ -772,7 +773,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -772,7 +773,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* the client wants us to do more in this compound: * the client wants us to do more in this compound:
*/ */
if (!nfsd4_last_compound_op(rqstp)) if (!nfsd4_last_compound_op(rqstp))
rqstp->rq_splice_ok = false; clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
/* check stateid */ /* check stateid */
if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
...@@ -1013,6 +1014,44 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1013,6 +1014,44 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return status; return status;
} }
static __be32
nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_fallocate *fallocate, int flags)
{
__be32 status = nfserr_notsupp;
struct file *file;
status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate,
&fallocate->falloc_stateid,
WR_STATE, &file);
if (status != nfs_ok) {
dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
return status;
}
status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, file,
fallocate->falloc_offset,
fallocate->falloc_length,
flags);
fput(file);
return status;
}
static __be32
nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_fallocate *fallocate)
{
return nfsd4_fallocate(rqstp, cstate, fallocate, 0);
}
static __be32
nfsd4_deallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_fallocate *fallocate)
{
return nfsd4_fallocate(rqstp, cstate, fallocate,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
}
static __be32 static __be32
nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_seek *seek) struct nfsd4_seek *seek)
...@@ -1331,7 +1370,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -1331,7 +1370,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
* Don't use the deferral mechanism for NFSv4; compounds make it * Don't use the deferral mechanism for NFSv4; compounds make it
* too hard to avoid non-idempotency problems. * too hard to avoid non-idempotency problems.
*/ */
rqstp->rq_usedeferral = false; clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
/* /*
* According to RFC3010, this takes precedence over all other errors. * According to RFC3010, this takes precedence over all other errors.
...@@ -1447,7 +1486,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -1447,7 +1486,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
BUG_ON(cstate->replay_owner); BUG_ON(cstate->replay_owner);
out: out:
/* Reset deferral mechanism for RPC deferrals */ /* Reset deferral mechanism for RPC deferrals */
rqstp->rq_usedeferral = true; set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
dprintk("nfsv4 compound returned %d\n", ntohl(status)); dprintk("nfsv4 compound returned %d\n", ntohl(status));
return status; return status;
} }
...@@ -1929,6 +1968,18 @@ static struct nfsd4_operation nfsd4_ops[] = { ...@@ -1929,6 +1968,18 @@ static struct nfsd4_operation nfsd4_ops[] = {
}, },
/* NFSv4.2 operations */ /* NFSv4.2 operations */
[OP_ALLOCATE] = {
.op_func = (nfsd4op_func)nfsd4_allocate,
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_ALLOCATE",
.op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
},
[OP_DEALLOCATE] = {
.op_func = (nfsd4op_func)nfsd4_deallocate,
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_DEALLOCATE",
.op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
},
[OP_SEEK] = { [OP_SEEK] = {
.op_func = (nfsd4op_func)nfsd4_seek, .op_func = (nfsd4op_func)nfsd4_seek,
.op_name = "OP_SEEK", .op_name = "OP_SEEK",
......
...@@ -275,9 +275,11 @@ opaque_hashval(const void *ptr, int nbytes) ...@@ -275,9 +275,11 @@ opaque_hashval(const void *ptr, int nbytes)
return x; return x;
} }
static void nfsd4_free_file(struct nfs4_file *f) static void nfsd4_free_file_rcu(struct rcu_head *rcu)
{ {
kmem_cache_free(file_slab, f); struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu);
kmem_cache_free(file_slab, fp);
} }
static inline void static inline void
...@@ -286,9 +288,10 @@ put_nfs4_file(struct nfs4_file *fi) ...@@ -286,9 +288,10 @@ put_nfs4_file(struct nfs4_file *fi)
might_lock(&state_lock); might_lock(&state_lock);
if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
hlist_del(&fi->fi_hash); hlist_del_rcu(&fi->fi_hash);
spin_unlock(&state_lock); spin_unlock(&state_lock);
nfsd4_free_file(fi); WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
} }
} }
...@@ -1440,7 +1443,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru ...@@ -1440,7 +1443,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
list_add(&new->se_perclnt, &clp->cl_sessions); list_add(&new->se_perclnt, &clp->cl_sessions);
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
if (cses->flags & SESSION4_BACK_CHAN) { {
struct sockaddr *sa = svc_addr(rqstp); struct sockaddr *sa = svc_addr(rqstp);
/* /*
* This is a little silly; with sessions there's no real * This is a little silly; with sessions there's no real
...@@ -1711,15 +1714,14 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) ...@@ -1711,15 +1714,14 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source)
return 0; return 0;
} }
static long long static int
compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
{ {
long long res; if (o1->len < o2->len)
return -1;
res = o1->len - o2->len; if (o1->len > o2->len)
if (res) return 1;
return res; return memcmp(o1->data, o2->data, o1->len);
return (long long)memcmp(o1->data, o2->data, o1->len);
} }
static int same_name(const char *n1, const char *n2) static int same_name(const char *n1, const char *n2)
...@@ -1907,7 +1909,7 @@ add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) ...@@ -1907,7 +1909,7 @@ add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
static struct nfs4_client * static struct nfs4_client *
find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
{ {
long long cmp; int cmp;
struct rb_node *node = root->rb_node; struct rb_node *node = root->rb_node;
struct nfs4_client *clp; struct nfs4_client *clp;
...@@ -3057,10 +3059,9 @@ static struct nfs4_file *nfsd4_alloc_file(void) ...@@ -3057,10 +3059,9 @@ static struct nfs4_file *nfsd4_alloc_file(void)
} }
/* OPEN Share state helper functions */ /* OPEN Share state helper functions */
static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
struct nfs4_file *fp)
{ {
unsigned int hashval = file_hashval(fh);
lockdep_assert_held(&state_lock); lockdep_assert_held(&state_lock);
atomic_set(&fp->fi_ref, 1); atomic_set(&fp->fi_ref, 1);
...@@ -3073,7 +3074,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) ...@@ -3073,7 +3074,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh)
fp->fi_share_deny = 0; fp->fi_share_deny = 0;
memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
memset(fp->fi_access, 0, sizeof(fp->fi_access)); memset(fp->fi_access, 0, sizeof(fp->fi_access));
hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]); hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
} }
void void
...@@ -3294,17 +3295,14 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) ...@@ -3294,17 +3295,14 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
/* search file_hashtbl[] for file */ /* search file_hashtbl[] for file */
static struct nfs4_file * static struct nfs4_file *
find_file_locked(struct knfsd_fh *fh) find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
{ {
unsigned int hashval = file_hashval(fh);
struct nfs4_file *fp; struct nfs4_file *fp;
lockdep_assert_held(&state_lock); hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) {
hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
if (nfsd_fh_match(&fp->fi_fhandle, fh)) { if (nfsd_fh_match(&fp->fi_fhandle, fh)) {
get_nfs4_file(fp); if (atomic_inc_not_zero(&fp->fi_ref))
return fp; return fp;
} }
} }
return NULL; return NULL;
...@@ -3314,10 +3312,11 @@ static struct nfs4_file * ...@@ -3314,10 +3312,11 @@ static struct nfs4_file *
find_file(struct knfsd_fh *fh) find_file(struct knfsd_fh *fh)
{ {
struct nfs4_file *fp; struct nfs4_file *fp;
unsigned int hashval = file_hashval(fh);
spin_lock(&state_lock); rcu_read_lock();
fp = find_file_locked(fh); fp = find_file_locked(fh, hashval);
spin_unlock(&state_lock); rcu_read_unlock();
return fp; return fp;
} }
...@@ -3325,11 +3324,18 @@ static struct nfs4_file * ...@@ -3325,11 +3324,18 @@ static struct nfs4_file *
find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh)
{ {
struct nfs4_file *fp; struct nfs4_file *fp;
unsigned int hashval = file_hashval(fh);
rcu_read_lock();
fp = find_file_locked(fh, hashval);
rcu_read_unlock();
if (fp)
return fp;
spin_lock(&state_lock); spin_lock(&state_lock);
fp = find_file_locked(fh); fp = find_file_locked(fh, hashval);
if (fp == NULL) { if (likely(fp == NULL)) {
nfsd4_init_file(new, fh); nfsd4_init_file(fh, hashval, new);
fp = new; fp = new;
} }
spin_unlock(&state_lock); spin_unlock(&state_lock);
...@@ -4127,7 +4133,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, ...@@ -4127,7 +4133,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
nfs4_put_stateowner(so); nfs4_put_stateowner(so);
} }
if (open->op_file) if (open->op_file)
nfsd4_free_file(open->op_file); kmem_cache_free(file_slab, open->op_file);
if (open->op_stp) if (open->op_stp)
nfs4_put_stid(&open->op_stp->st_stid); nfs4_put_stid(&open->op_stp->st_stid);
} }
......
...@@ -1513,6 +1513,23 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str ...@@ -1513,6 +1513,23 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str
DECODE_TAIL; DECODE_TAIL;
} }
static __be32
nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
struct nfsd4_fallocate *fallocate)
{
DECODE_HEAD;
status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid);
if (status)
return status;
READ_BUF(16);
p = xdr_decode_hyper(p, &fallocate->falloc_offset);
xdr_decode_hyper(p, &fallocate->falloc_length);
DECODE_TAIL;
}
static __be32 static __be32
nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
{ {
...@@ -1604,10 +1621,10 @@ static nfsd4_dec nfsd4_dec_ops[] = { ...@@ -1604,10 +1621,10 @@ static nfsd4_dec nfsd4_dec_ops[] = {
[OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
/* new operations for NFSv4.2 */ /* new operations for NFSv4.2 */
[OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
...@@ -1714,7 +1731,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1714,7 +1731,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack)
argp->rqstp->rq_splice_ok = false; clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
DECODE_TAIL; DECODE_TAIL;
} }
...@@ -1795,9 +1812,12 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep, ...@@ -1795,9 +1812,12 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
} }
else else
end++; end++;
if (found_esc)
end = next;
str = end; str = end;
} }
pathlen = htonl(xdr->buf->len - pathlen_offset); pathlen = htonl(count);
write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4); write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
return 0; return 0;
} }
...@@ -3236,10 +3256,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3236,10 +3256,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
if (!p) { if (!p) {
WARN_ON_ONCE(resp->rqstp->rq_splice_ok); WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
return nfserr_resource; return nfserr_resource;
} }
if (resp->xdr.buf->page_len && resp->rqstp->rq_splice_ok) { if (resp->xdr.buf->page_len && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return nfserr_resource; return nfserr_resource;
} }
...@@ -3256,7 +3276,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -3256,7 +3276,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
goto err_truncate; goto err_truncate;
} }
if (file->f_op->splice_read && resp->rqstp->rq_splice_ok) if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
err = nfsd4_encode_splice_read(resp, read, file, maxcount); err = nfsd4_encode_splice_read(resp, read, file, maxcount);
else else
err = nfsd4_encode_readv(resp, read, file, maxcount); err = nfsd4_encode_readv(resp, read, file, maxcount);
......
...@@ -490,7 +490,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp) ...@@ -490,7 +490,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
/* From the hall of fame of impractical attacks: /* From the hall of fame of impractical attacks:
* Is this a user who tries to snoop on the cache? */ * Is this a user who tries to snoop on the cache? */
rtn = RC_DOIT; rtn = RC_DOIT;
if (!rqstp->rq_secure && rp->c_secure) if (!test_bit(RQ_SECURE, &rqstp->rq_flags) && rp->c_secure)
goto out; goto out;
/* Compose RPC reply header */ /* Compose RPC reply header */
...@@ -579,7 +579,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) ...@@ -579,7 +579,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
spin_lock(&b->cache_lock); spin_lock(&b->cache_lock);
drc_mem_usage += bufsize; drc_mem_usage += bufsize;
lru_put_end(b, rp); lru_put_end(b, rp);
rp->c_secure = rqstp->rq_secure; rp->c_secure = test_bit(RQ_SECURE, &rqstp->rq_flags);
rp->c_type = cachetype; rp->c_type = cachetype;
rp->c_state = RC_DONE; rp->c_state = RC_DONE;
spin_unlock(&b->cache_lock); spin_unlock(&b->cache_lock);
......
...@@ -608,7 +608,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) ...@@ -608,7 +608,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
num); num);
sep = " "; sep = " ";
if (len > remaining) if (len >= remaining)
break; break;
remaining -= len; remaining -= len;
buf += len; buf += len;
...@@ -623,7 +623,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) ...@@ -623,7 +623,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
'+' : '-', '+' : '-',
minor); minor);
if (len > remaining) if (len >= remaining)
break; break;
remaining -= len; remaining -= len;
buf += len; buf += len;
...@@ -631,7 +631,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) ...@@ -631,7 +631,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
} }
len = snprintf(buf, remaining, "\n"); len = snprintf(buf, remaining, "\n");
if (len > remaining) if (len >= remaining)
return -EINVAL; return -EINVAL;
return tlen + len; return tlen + len;
} }
......
...@@ -86,7 +86,7 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, ...@@ -86,7 +86,7 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
int flags = nfsexp_flags(rqstp, exp); int flags = nfsexp_flags(rqstp, exp);
/* Check if the request originated from a secure port. */ /* Check if the request originated from a secure port. */
if (!rqstp->rq_secure && !(flags & NFSEXP_INSECURE_PORT)) { if (!test_bit(RQ_SECURE, &rqstp->rq_flags) && !(flags & NFSEXP_INSECURE_PORT)) {
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
dprintk("nfsd: request from insecure port %s!\n", dprintk("nfsd: request from insecure port %s!\n",
svc_print_addr(rqstp, buf, sizeof(buf))); svc_print_addr(rqstp, buf, sizeof(buf)));
......
...@@ -692,7 +692,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) ...@@ -692,7 +692,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
/* Now call the procedure handler, and encode NFS status. */ /* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
nfserr = map_new_errors(rqstp->rq_vers, nfserr); nfserr = map_new_errors(rqstp->rq_vers, nfserr);
if (nfserr == nfserr_dropit || rqstp->rq_dropme) { if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) {
dprintk("nfsd: Dropping request; may be revisited later\n"); dprintk("nfsd: Dropping request; may be revisited later\n");
nfsd_cache_update(rqstp, RC_NOCACHE, NULL); nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
return 0; return 0;
......
...@@ -463,17 +463,24 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) ...@@ -463,17 +463,24 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
/* /*
* nfs4_file: a file opened by some number of (open) nfs4_stateowners. * nfs4_file: a file opened by some number of (open) nfs4_stateowners.
* *
* These objects are global. nfsd only keeps one instance of a nfs4_file per * These objects are global. nfsd keeps one instance of a nfs4_file per
* inode (though it may keep multiple file descriptors open per inode). These * filehandle (though it may keep multiple file descriptors for each). Each
* are tracked in the file_hashtbl which is protected by the state_lock * inode can have multiple filehandles associated with it, so there is
* spinlock. * (potentially) a many to one relationship between this struct and struct
* inode.
*
* These are hashed by filehandle in the file_hashtbl, which is protected by
* the global state_lock spinlock.
*/ */
struct nfs4_file { struct nfs4_file {
atomic_t fi_ref; atomic_t fi_ref;
spinlock_t fi_lock; spinlock_t fi_lock;
struct hlist_node fi_hash; /* hash by "struct inode *" */ struct hlist_node fi_hash; /* hash on fi_fhandle */
struct list_head fi_stateids; struct list_head fi_stateids;
struct list_head fi_delegations; union {
struct list_head fi_delegations;
struct rcu_head fi_rcu;
};
/* One each for O_RDONLY, O_WRONLY, O_RDWR: */ /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
struct file * fi_fds[3]; struct file * fi_fds[3];
/* /*
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/splice.h> #include <linux/splice.h>
#include <linux/falloc.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -533,6 +534,26 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -533,6 +534,26 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
} }
#endif #endif
__be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct file *file, loff_t offset, loff_t len,
int flags)
{
__be32 err;
int error;
if (!S_ISREG(file_inode(file)->i_mode))
return nfserr_inval;
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, NFSD_MAY_WRITE);
if (err)
return err;
error = vfs_fallocate(file, flags, offset, len);
if (!error)
error = commit_metadata(fhp);
return nfserrno(error);
}
#endif /* defined(CONFIG_NFSD_V4) */ #endif /* defined(CONFIG_NFSD_V4) */
#ifdef CONFIG_NFSD_V3 #ifdef CONFIG_NFSD_V3
...@@ -881,7 +902,7 @@ static __be32 ...@@ -881,7 +902,7 @@ static __be32
nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file, nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count) loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{ {
if (file->f_op->splice_read && rqstp->rq_splice_ok) if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
return nfsd_splice_read(rqstp, file, offset, count); return nfsd_splice_read(rqstp, file, offset, count);
else else
return nfsd_readv(file, offset, vec, vlen, count); return nfsd_readv(file, offset, vec, vlen, count);
...@@ -937,9 +958,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -937,9 +958,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
int stable = *stablep; int stable = *stablep;
int use_wgather; int use_wgather;
loff_t pos = offset; loff_t pos = offset;
loff_t end = LLONG_MAX;
unsigned int pflags = current->flags; unsigned int pflags = current->flags;
if (rqstp->rq_local) if (test_bit(RQ_LOCAL, &rqstp->rq_flags))
/* /*
* We want less throttling in balance_dirty_pages() * We want less throttling in balance_dirty_pages()
* and shrink_inactive_list() so that nfs to * and shrink_inactive_list() so that nfs to
...@@ -967,10 +989,13 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -967,10 +989,13 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
fsnotify_modify(file); fsnotify_modify(file);
if (stable) { if (stable) {
if (use_wgather) if (use_wgather) {
host_err = wait_for_concurrent_writes(file); host_err = wait_for_concurrent_writes(file);
else } else {
host_err = vfs_fsync_range(file, offset, offset+*cnt, 0); if (*cnt)
end = offset + *cnt - 1;
host_err = vfs_fsync_range(file, offset, end, 0);
}
} }
out_nfserr: out_nfserr:
...@@ -979,7 +1004,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -979,7 +1004,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
err = 0; err = 0;
else else
err = nfserrno(host_err); err = nfserrno(host_err);
if (rqstp->rq_local) if (test_bit(RQ_LOCAL, &rqstp->rq_flags))
tsk_restore_flags(current, pflags, PF_LESS_THROTTLE); tsk_restore_flags(current, pflags, PF_LESS_THROTTLE);
return err; return err;
} }
......
...@@ -54,6 +54,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *); ...@@ -54,6 +54,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
#ifdef CONFIG_NFSD_V4 #ifdef CONFIG_NFSD_V4
__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
struct xdr_netobj *); struct xdr_netobj *);
__be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
struct file *, loff_t, loff_t, int);
#endif /* CONFIG_NFSD_V4 */ #endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *, __be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs, char *name, int len, struct iattr *attrs,
......
...@@ -428,6 +428,13 @@ struct nfsd4_reclaim_complete { ...@@ -428,6 +428,13 @@ struct nfsd4_reclaim_complete {
u32 rca_one_fs; u32 rca_one_fs;
}; };
struct nfsd4_fallocate {
/* request */
stateid_t falloc_stateid;
loff_t falloc_offset;
u64 falloc_length;
};
struct nfsd4_seek { struct nfsd4_seek {
/* request */ /* request */
stateid_t seek_stateid; stateid_t seek_stateid;
...@@ -486,6 +493,8 @@ struct nfsd4_op { ...@@ -486,6 +493,8 @@ struct nfsd4_op {
struct nfsd4_free_stateid free_stateid; struct nfsd4_free_stateid free_stateid;
/* NFSv4.2 */ /* NFSv4.2 */
struct nfsd4_fallocate allocate;
struct nfsd4_fallocate deallocate;
struct nfsd4_seek seek; struct nfsd4_seek seek;
} u; } u;
struct nfs4_replay * replay; struct nfs4_replay * replay;
......
...@@ -222,7 +222,7 @@ SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length) ...@@ -222,7 +222,7 @@ SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
#endif /* BITS_PER_LONG == 32 */ #endif /* BITS_PER_LONG == 32 */
int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
long ret; long ret;
...@@ -309,6 +309,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -309,6 +309,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
sb_end_write(inode->i_sb); sb_end_write(inode->i_sb);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(vfs_fallocate);
SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
{ {
...@@ -316,7 +317,7 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) ...@@ -316,7 +317,7 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
int error = -EBADF; int error = -EBADF;
if (f.file) { if (f.file) {
error = do_fallocate(f.file, mode, offset, len); error = vfs_fallocate(f.file, mode, offset, len);
fdput(f); fdput(f);
} }
return error; return error;
......
...@@ -2086,7 +2086,7 @@ struct filename { ...@@ -2086,7 +2086,7 @@ struct filename {
extern long vfs_truncate(struct path *, loff_t); extern long vfs_truncate(struct path *, loff_t);
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp); struct file *filp);
extern int do_fallocate(struct file *file, int mode, loff_t offset, extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
loff_t len); loff_t len);
extern long do_sys_open(int dfd, const char __user *filename, int flags, extern long do_sys_open(int dfd, const char __user *filename, int flags,
umode_t mode); umode_t mode);
......
...@@ -26,10 +26,10 @@ typedef int (*svc_thread_fn)(void *); ...@@ -26,10 +26,10 @@ typedef int (*svc_thread_fn)(void *);
/* statistics for svc_pool structures */ /* statistics for svc_pool structures */
struct svc_pool_stats { struct svc_pool_stats {
unsigned long packets; atomic_long_t packets;
unsigned long sockets_queued; unsigned long sockets_queued;
unsigned long threads_woken; atomic_long_t threads_woken;
unsigned long threads_timedout; atomic_long_t threads_timedout;
}; };
/* /*
...@@ -45,12 +45,13 @@ struct svc_pool_stats { ...@@ -45,12 +45,13 @@ struct svc_pool_stats {
struct svc_pool { struct svc_pool {
unsigned int sp_id; /* pool id; also node id on NUMA */ unsigned int sp_id; /* pool id; also node id on NUMA */
spinlock_t sp_lock; /* protects all fields */ spinlock_t sp_lock; /* protects all fields */
struct list_head sp_threads; /* idle server threads */
struct list_head sp_sockets; /* pending sockets */ struct list_head sp_sockets; /* pending sockets */
unsigned int sp_nrthreads; /* # of threads in pool */ unsigned int sp_nrthreads; /* # of threads in pool */
struct list_head sp_all_threads; /* all server threads */ struct list_head sp_all_threads; /* all server threads */
struct svc_pool_stats sp_stats; /* statistics on pool operation */ struct svc_pool_stats sp_stats; /* statistics on pool operation */
int sp_task_pending;/* has pending task */ #define SP_TASK_PENDING (0) /* still work to do even if no
* xprt is queued. */
unsigned long sp_flags;
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
/* /*
...@@ -219,8 +220,8 @@ static inline void svc_putu32(struct kvec *iov, __be32 val) ...@@ -219,8 +220,8 @@ static inline void svc_putu32(struct kvec *iov, __be32 val)
* processed. * processed.
*/ */
struct svc_rqst { struct svc_rqst {
struct list_head rq_list; /* idle list */
struct list_head rq_all; /* all threads list */ struct list_head rq_all; /* all threads list */
struct rcu_head rq_rcu_head; /* for RCU deferred kfree */
struct svc_xprt * rq_xprt; /* transport ptr */ struct svc_xprt * rq_xprt; /* transport ptr */
struct sockaddr_storage rq_addr; /* peer address */ struct sockaddr_storage rq_addr; /* peer address */
...@@ -236,7 +237,6 @@ struct svc_rqst { ...@@ -236,7 +237,6 @@ struct svc_rqst {
struct svc_cred rq_cred; /* auth info */ struct svc_cred rq_cred; /* auth info */
void * rq_xprt_ctxt; /* transport specific context ptr */ void * rq_xprt_ctxt; /* transport specific context ptr */
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
bool rq_usedeferral; /* use deferral */
size_t rq_xprt_hlen; /* xprt header len */ size_t rq_xprt_hlen; /* xprt header len */
struct xdr_buf rq_arg; struct xdr_buf rq_arg;
...@@ -253,9 +253,17 @@ struct svc_rqst { ...@@ -253,9 +253,17 @@ struct svc_rqst {
u32 rq_vers; /* program version */ u32 rq_vers; /* program version */
u32 rq_proc; /* procedure number */ u32 rq_proc; /* procedure number */
u32 rq_prot; /* IP protocol */ u32 rq_prot; /* IP protocol */
unsigned short int rq_cachetype; /* catering to nfsd */
rq_secure : 1; /* secure port */ #define RQ_SECURE (0) /* secure port */
unsigned short rq_local : 1; /* local request */ #define RQ_LOCAL (1) /* local request */
#define RQ_USEDEFERRAL (2) /* use deferral */
#define RQ_DROPME (3) /* drop current reply */
#define RQ_SPLICE_OK (4) /* turned off in gss privacy
* to prevent encrypting page
* cache pages */
#define RQ_VICTIM (5) /* about to be shut down */
#define RQ_BUSY (6) /* request is busy */
unsigned long rq_flags; /* flags field */
void * rq_argp; /* decoded arguments */ void * rq_argp; /* decoded arguments */
void * rq_resp; /* xdr'd results */ void * rq_resp; /* xdr'd results */
...@@ -271,16 +279,12 @@ struct svc_rqst { ...@@ -271,16 +279,12 @@ struct svc_rqst {
struct cache_req rq_chandle; /* handle passed to caches for struct cache_req rq_chandle; /* handle passed to caches for
* request delaying * request delaying
*/ */
bool rq_dropme;
/* Catering to nfsd */ /* Catering to nfsd */
struct auth_domain * rq_client; /* RPC peer info */ struct auth_domain * rq_client; /* RPC peer info */
struct auth_domain * rq_gssclient; /* "gss/"-style peer info */ struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
int rq_cachetype;
struct svc_cacherep * rq_cacherep; /* cache info */ struct svc_cacherep * rq_cacherep; /* cache info */
bool rq_splice_ok; /* turned off in gss privacy
* to prevent encrypting page
* cache pages */
struct task_struct *rq_task; /* service thread */ struct task_struct *rq_task; /* service thread */
spinlock_t rq_lock; /* per-request lock */
}; };
#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net) #define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net)
......
...@@ -63,10 +63,9 @@ struct svc_xprt { ...@@ -63,10 +63,9 @@ struct svc_xprt {
#define XPT_CHNGBUF 7 /* need to change snd/rcv buf sizes */ #define XPT_CHNGBUF 7 /* need to change snd/rcv buf sizes */
#define XPT_DEFERRED 8 /* deferred request pending */ #define XPT_DEFERRED 8 /* deferred request pending */
#define XPT_OLD 9 /* used for xprt aging mark+sweep */ #define XPT_OLD 9 /* used for xprt aging mark+sweep */
#define XPT_DETACHED 10 /* detached from tempsocks list */ #define XPT_LISTENER 10 /* listening endpoint */
#define XPT_LISTENER 11 /* listening endpoint */ #define XPT_CACHE_AUTH 11 /* cache auth info */
#define XPT_CACHE_AUTH 12 /* cache auth info */ #define XPT_LOCAL 12 /* connection from loopback interface */
#define XPT_LOCAL 13 /* connection from loopback interface */
struct svc_serv *xpt_server; /* service for transport */ struct svc_serv *xpt_server; /* service for transport */
atomic_t xpt_reserved; /* space on outq that is rsvd */ atomic_t xpt_reserved; /* space on outq that is rsvd */
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/sunrpc/xprtsock.h> #include <linux/sunrpc/xprtsock.h>
#include <linux/sunrpc/svc_xprt.h>
#include <net/tcp_states.h> #include <net/tcp_states.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
...@@ -412,6 +413,16 @@ TRACE_EVENT(xs_tcp_data_recv, ...@@ -412,6 +413,16 @@ TRACE_EVENT(xs_tcp_data_recv,
__entry->copied, __entry->reclen, __entry->offset) __entry->copied, __entry->reclen, __entry->offset)
); );
#define show_rqstp_flags(flags) \
__print_flags(flags, "|", \
{ (1UL << RQ_SECURE), "RQ_SECURE"}, \
{ (1UL << RQ_LOCAL), "RQ_LOCAL"}, \
{ (1UL << RQ_USEDEFERRAL), "RQ_USEDEFERRAL"}, \
{ (1UL << RQ_DROPME), "RQ_DROPME"}, \
{ (1UL << RQ_SPLICE_OK), "RQ_SPLICE_OK"}, \
{ (1UL << RQ_VICTIM), "RQ_VICTIM"}, \
{ (1UL << RQ_BUSY), "RQ_BUSY"})
TRACE_EVENT(svc_recv, TRACE_EVENT(svc_recv,
TP_PROTO(struct svc_rqst *rqst, int status), TP_PROTO(struct svc_rqst *rqst, int status),
...@@ -421,16 +432,19 @@ TRACE_EVENT(svc_recv, ...@@ -421,16 +432,19 @@ TRACE_EVENT(svc_recv,
__field(struct sockaddr *, addr) __field(struct sockaddr *, addr)
__field(__be32, xid) __field(__be32, xid)
__field(int, status) __field(int, status)
__field(unsigned long, flags)
), ),
TP_fast_assign( TP_fast_assign(
__entry->addr = (struct sockaddr *)&rqst->rq_addr; __entry->addr = (struct sockaddr *)&rqst->rq_addr;
__entry->xid = status > 0 ? rqst->rq_xid : 0; __entry->xid = status > 0 ? rqst->rq_xid : 0;
__entry->status = status; __entry->status = status;
__entry->flags = rqst->rq_flags;
), ),
TP_printk("addr=%pIScp xid=0x%x status=%d", __entry->addr, TP_printk("addr=%pIScp xid=0x%x status=%d flags=%s", __entry->addr,
be32_to_cpu(__entry->xid), __entry->status) be32_to_cpu(__entry->xid), __entry->status,
show_rqstp_flags(__entry->flags))
); );
DECLARE_EVENT_CLASS(svc_rqst_status, DECLARE_EVENT_CLASS(svc_rqst_status,
...@@ -444,18 +458,19 @@ DECLARE_EVENT_CLASS(svc_rqst_status, ...@@ -444,18 +458,19 @@ DECLARE_EVENT_CLASS(svc_rqst_status,
__field(__be32, xid) __field(__be32, xid)
__field(int, dropme) __field(int, dropme)
__field(int, status) __field(int, status)
__field(unsigned long, flags)
), ),
TP_fast_assign( TP_fast_assign(
__entry->addr = (struct sockaddr *)&rqst->rq_addr; __entry->addr = (struct sockaddr *)&rqst->rq_addr;
__entry->xid = rqst->rq_xid; __entry->xid = rqst->rq_xid;
__entry->dropme = (int)rqst->rq_dropme;
__entry->status = status; __entry->status = status;
__entry->flags = rqst->rq_flags;
), ),
TP_printk("addr=%pIScp rq_xid=0x%x dropme=%d status=%d", TP_printk("addr=%pIScp rq_xid=0x%x status=%d flags=%s",
__entry->addr, be32_to_cpu(__entry->xid), __entry->dropme, __entry->addr, be32_to_cpu(__entry->xid),
__entry->status) __entry->status, show_rqstp_flags(__entry->flags))
); );
DEFINE_EVENT(svc_rqst_status, svc_process, DEFINE_EVENT(svc_rqst_status, svc_process,
...@@ -466,6 +481,99 @@ DEFINE_EVENT(svc_rqst_status, svc_send, ...@@ -466,6 +481,99 @@ DEFINE_EVENT(svc_rqst_status, svc_send,
TP_PROTO(struct svc_rqst *rqst, int status), TP_PROTO(struct svc_rqst *rqst, int status),
TP_ARGS(rqst, status)); TP_ARGS(rqst, status));
#define show_svc_xprt_flags(flags) \
__print_flags(flags, "|", \
{ (1UL << XPT_BUSY), "XPT_BUSY"}, \
{ (1UL << XPT_CONN), "XPT_CONN"}, \
{ (1UL << XPT_CLOSE), "XPT_CLOSE"}, \
{ (1UL << XPT_DATA), "XPT_DATA"}, \
{ (1UL << XPT_TEMP), "XPT_TEMP"}, \
{ (1UL << XPT_DEAD), "XPT_DEAD"}, \
{ (1UL << XPT_CHNGBUF), "XPT_CHNGBUF"}, \
{ (1UL << XPT_DEFERRED), "XPT_DEFERRED"}, \
{ (1UL << XPT_OLD), "XPT_OLD"}, \
{ (1UL << XPT_LISTENER), "XPT_LISTENER"}, \
{ (1UL << XPT_CACHE_AUTH), "XPT_CACHE_AUTH"}, \
{ (1UL << XPT_LOCAL), "XPT_LOCAL"})
TRACE_EVENT(svc_xprt_do_enqueue,
TP_PROTO(struct svc_xprt *xprt, struct svc_rqst *rqst),
TP_ARGS(xprt, rqst),
TP_STRUCT__entry(
__field(struct svc_xprt *, xprt)
__field(struct svc_rqst *, rqst)
),
TP_fast_assign(
__entry->xprt = xprt;
__entry->rqst = rqst;
),
TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt,
(struct sockaddr *)&__entry->xprt->xpt_remote,
__entry->rqst ? __entry->rqst->rq_task->pid : 0,
show_svc_xprt_flags(__entry->xprt->xpt_flags))
);
TRACE_EVENT(svc_xprt_dequeue,
TP_PROTO(struct svc_xprt *xprt),
TP_ARGS(xprt),
TP_STRUCT__entry(
__field(struct svc_xprt *, xprt)
__field_struct(struct sockaddr_storage, ss)
__field(unsigned long, flags)
),
TP_fast_assign(
__entry->xprt = xprt,
xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
__entry->flags = xprt ? xprt->xpt_flags : 0;
),
TP_printk("xprt=0x%p addr=%pIScp flags=%s", __entry->xprt,
(struct sockaddr *)&__entry->ss,
show_svc_xprt_flags(__entry->flags))
);
TRACE_EVENT(svc_wake_up,
TP_PROTO(int pid),
TP_ARGS(pid),
TP_STRUCT__entry(
__field(int, pid)
),
TP_fast_assign(
__entry->pid = pid;
),
TP_printk("pid=%d", __entry->pid)
);
TRACE_EVENT(svc_handle_xprt,
TP_PROTO(struct svc_xprt *xprt, int len),
TP_ARGS(xprt, len),
TP_STRUCT__entry(
__field(struct svc_xprt *, xprt)
__field(int, len)
),
TP_fast_assign(
__entry->xprt = xprt;
__entry->len = len;
),
TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt,
(struct sockaddr *)&__entry->xprt->xpt_remote, __entry->len,
show_svc_xprt_flags(__entry->xprt->xpt_flags))
);
#endif /* _TRACE_SUNRPC_H */ #endif /* _TRACE_SUNRPC_H */
#include <trace/define_trace.h> #include <trace/define_trace.h>
...@@ -326,7 +326,7 @@ static long madvise_remove(struct vm_area_struct *vma, ...@@ -326,7 +326,7 @@ static long madvise_remove(struct vm_area_struct *vma,
*/ */
get_file(f); get_file(f);
up_read(&current->mm->mmap_sem); up_read(&current->mm->mmap_sem);
error = do_fallocate(f, error = vfs_fallocate(f,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
offset, end - start); offset, end - start);
fput(f); fput(f);
......
...@@ -886,7 +886,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs ...@@ -886,7 +886,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs
u32 priv_len, maj_stat; u32 priv_len, maj_stat;
int pad, saved_len, remaining_len, offset; int pad, saved_len, remaining_len, offset;
rqstp->rq_splice_ok = false; clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
priv_len = svc_getnl(&buf->head[0]); priv_len = svc_getnl(&buf->head[0]);
if (rqstp->rq_deferred) { if (rqstp->rq_deferred) {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/string_helpers.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -1067,30 +1068,15 @@ void qword_add(char **bpp, int *lp, char *str) ...@@ -1067,30 +1068,15 @@ void qword_add(char **bpp, int *lp, char *str)
{ {
char *bp = *bpp; char *bp = *bpp;
int len = *lp; int len = *lp;
char c; int ret;
if (len < 0) return; if (len < 0) return;
while ((c=*str++) && len) ret = string_escape_str(str, &bp, len, ESCAPE_OCTAL, "\\ \n\t");
switch(c) { if (ret < 0 || ret == len)
case ' ': len = -1;
case '\t':
case '\n':
case '\\':
if (len >= 4) {
*bp++ = '\\';
*bp++ = '0' + ((c & 0300)>>6);
*bp++ = '0' + ((c & 0070)>>3);
*bp++ = '0' + ((c & 0007)>>0);
}
len -= 4;
break;
default:
*bp++ = c;
len--;
}
if (c || len <1) len = -1;
else { else {
len -= ret;
*bp++ = ' '; *bp++ = ' ';
len--; len--;
} }
......
...@@ -191,7 +191,7 @@ svc_pool_map_init_percpu(struct svc_pool_map *m) ...@@ -191,7 +191,7 @@ svc_pool_map_init_percpu(struct svc_pool_map *m)
return err; return err;
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
BUG_ON(pidx > maxpools); BUG_ON(pidx >= maxpools);
m->to_pool[cpu] = pidx; m->to_pool[cpu] = pidx;
m->pool_to[pidx] = cpu; m->pool_to[pidx] = cpu;
pidx++; pidx++;
...@@ -476,15 +476,11 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, ...@@ -476,15 +476,11 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
i, serv->sv_name); i, serv->sv_name);
pool->sp_id = i; pool->sp_id = i;
INIT_LIST_HEAD(&pool->sp_threads);
INIT_LIST_HEAD(&pool->sp_sockets); INIT_LIST_HEAD(&pool->sp_sockets);
INIT_LIST_HEAD(&pool->sp_all_threads); INIT_LIST_HEAD(&pool->sp_all_threads);
spin_lock_init(&pool->sp_lock); spin_lock_init(&pool->sp_lock);
} }
if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown))
serv->sv_shutdown = svc_rpcb_cleanup;
return serv; return serv;
} }
...@@ -505,13 +501,15 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, ...@@ -505,13 +501,15 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
unsigned int npools = svc_pool_map_get(); unsigned int npools = svc_pool_map_get();
serv = __svc_create(prog, bufsize, npools, shutdown); serv = __svc_create(prog, bufsize, npools, shutdown);
if (!serv)
goto out_err;
if (serv != NULL) { serv->sv_function = func;
serv->sv_function = func; serv->sv_module = mod;
serv->sv_module = mod;
}
return serv; return serv;
out_err:
svc_pool_map_put();
return NULL;
} }
EXPORT_SYMBOL_GPL(svc_create_pooled); EXPORT_SYMBOL_GPL(svc_create_pooled);
...@@ -615,12 +613,14 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) ...@@ -615,12 +613,14 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
goto out_enomem; goto out_enomem;
serv->sv_nrthreads++; serv->sv_nrthreads++;
__set_bit(RQ_BUSY, &rqstp->rq_flags);
spin_lock_init(&rqstp->rq_lock);
rqstp->rq_server = serv;
rqstp->rq_pool = pool;
spin_lock_bh(&pool->sp_lock); spin_lock_bh(&pool->sp_lock);
pool->sp_nrthreads++; pool->sp_nrthreads++;
list_add(&rqstp->rq_all, &pool->sp_all_threads); list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads);
spin_unlock_bh(&pool->sp_lock); spin_unlock_bh(&pool->sp_lock);
rqstp->rq_server = serv;
rqstp->rq_pool = pool;
rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
if (!rqstp->rq_argp) if (!rqstp->rq_argp)
...@@ -685,7 +685,8 @@ choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) ...@@ -685,7 +685,8 @@ choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
* so we don't try to kill it again. * so we don't try to kill it again.
*/ */
rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
list_del_init(&rqstp->rq_all); set_bit(RQ_VICTIM, &rqstp->rq_flags);
list_del_rcu(&rqstp->rq_all);
task = rqstp->rq_task; task = rqstp->rq_task;
} }
spin_unlock_bh(&pool->sp_lock); spin_unlock_bh(&pool->sp_lock);
...@@ -783,10 +784,11 @@ svc_exit_thread(struct svc_rqst *rqstp) ...@@ -783,10 +784,11 @@ svc_exit_thread(struct svc_rqst *rqstp)
spin_lock_bh(&pool->sp_lock); spin_lock_bh(&pool->sp_lock);
pool->sp_nrthreads--; pool->sp_nrthreads--;
list_del(&rqstp->rq_all); if (!test_and_set_bit(RQ_VICTIM, &rqstp->rq_flags))
list_del_rcu(&rqstp->rq_all);
spin_unlock_bh(&pool->sp_lock); spin_unlock_bh(&pool->sp_lock);
kfree(rqstp); kfree_rcu(rqstp, rq_rcu_head);
/* Release the server */ /* Release the server */
if (serv) if (serv)
...@@ -1086,10 +1088,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1086,10 +1088,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
goto err_short_len; goto err_short_len;
/* Will be turned off only in gss privacy case: */ /* Will be turned off only in gss privacy case: */
rqstp->rq_splice_ok = true; set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
/* Will be turned off only when NFSv4 Sessions are used */ /* Will be turned off only when NFSv4 Sessions are used */
rqstp->rq_usedeferral = true; set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
rqstp->rq_dropme = false; clear_bit(RQ_DROPME, &rqstp->rq_flags);
/* Setup reply header */ /* Setup reply header */
rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
...@@ -1189,7 +1191,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) ...@@ -1189,7 +1191,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
/* Encode reply */ /* Encode reply */
if (rqstp->rq_dropme) { if (test_bit(RQ_DROPME, &rqstp->rq_flags)) {
if (procp->pc_release) if (procp->pc_release)
procp->pc_release(rqstp, NULL, rqstp->rq_resp); procp->pc_release(rqstp, NULL, rqstp->rq_resp);
goto dropit; goto dropit;
......
This diff is collapsed.
...@@ -1145,7 +1145,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) ...@@ -1145,7 +1145,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
rqstp->rq_xprt_ctxt = NULL; rqstp->rq_xprt_ctxt = NULL;
rqstp->rq_prot = IPPROTO_TCP; rqstp->rq_prot = IPPROTO_TCP;
rqstp->rq_local = !!test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags); if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags))
set_bit(RQ_LOCAL, &rqstp->rq_flags);
else
clear_bit(RQ_LOCAL, &rqstp->rq_flags);
p = (__be32 *)rqstp->rq_arg.head[0].iov_base; p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
calldir = p[1]; calldir = p[1];
......
...@@ -617,9 +617,10 @@ void xdr_truncate_encode(struct xdr_stream *xdr, size_t len) ...@@ -617,9 +617,10 @@ void xdr_truncate_encode(struct xdr_stream *xdr, size_t len)
fraglen = min_t(int, buf->len - len, tail->iov_len); fraglen = min_t(int, buf->len - len, tail->iov_len);
tail->iov_len -= fraglen; tail->iov_len -= fraglen;
buf->len -= fraglen; buf->len -= fraglen;
if (tail->iov_len && buf->len == len) { if (tail->iov_len) {
xdr->p = tail->iov_base + tail->iov_len; xdr->p = tail->iov_base + tail->iov_len;
/* xdr->end, xdr->iov should be set already */ WARN_ON_ONCE(!xdr->end);
WARN_ON_ONCE(!xdr->iov);
return; return;
} }
WARN_ON_ONCE(fraglen); WARN_ON_ONCE(fraglen);
...@@ -631,11 +632,11 @@ void xdr_truncate_encode(struct xdr_stream *xdr, size_t len) ...@@ -631,11 +632,11 @@ void xdr_truncate_encode(struct xdr_stream *xdr, size_t len)
old = new + fraglen; old = new + fraglen;
xdr->page_ptr -= (old >> PAGE_SHIFT) - (new >> PAGE_SHIFT); xdr->page_ptr -= (old >> PAGE_SHIFT) - (new >> PAGE_SHIFT);
if (buf->page_len && buf->len == len) { if (buf->page_len) {
xdr->p = page_address(*xdr->page_ptr); xdr->p = page_address(*xdr->page_ptr);
xdr->end = (void *)xdr->p + PAGE_SIZE; xdr->end = (void *)xdr->p + PAGE_SIZE;
xdr->p = (void *)xdr->p + (new % PAGE_SIZE); xdr->p = (void *)xdr->p + (new % PAGE_SIZE);
/* xdr->iov should already be NULL */ WARN_ON_ONCE(xdr->iov);
return; return;
} }
if (fraglen) { if (fraglen) {
......
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