Commit e394ff83 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd updates from Chuck Lever:
 "Work on 'courteous server', which was introduced in 5.19, continues
  apace. This release introduces a more flexible limit on the number of
  NFSv4 clients that NFSD allows, now that NFSv4 clients can remain in
  courtesy state long after the lease expiration timeout. The client
  limit is adjusted based on the physical memory size of the server.

  The NFSD filecache is a cache of files held open by NFSv4 clients or
  recently touched by NFSv2 or NFSv3 clients. This cache had some
  significant scalability constraints that have been relieved in this
  release. Thanks to all who contributed to this work.

  A data corruption bug found during the most recent NFS bake-a-thon
  that involves NFSv3 and NFSv4 clients writing the same file has been
  addressed in this release.

  This release includes several improvements in CPU scalability for
  NFSv4 operations. In addition, Neil Brown provided patches that
  simplify locking during file lookup, creation, rename, and removal
  that enables subsequent work on making these operations more scalable.
  We expect to see that work materialize in the next release.

  There are also numerous single-patch fixes, clean-ups, and the usual
  improvements in observability"

* tag 'nfsd-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (78 commits)
  lockd: detect and reject lock arguments that overflow
  NFSD: discard fh_locked flag and fh_lock/fh_unlock
  NFSD: use (un)lock_inode instead of fh_(un)lock for file operations
  NFSD: use explicit lock/unlock for directory ops
  NFSD: reduce locking in nfsd_lookup()
  NFSD: only call fh_unlock() once in nfsd_link()
  NFSD: always drop directory lock in nfsd_unlink()
  NFSD: change nfsd_create()/nfsd_symlink() to unlock directory before returning.
  NFSD: add posix ACLs to struct nfsd_attrs
  NFSD: add security label to struct nfsd_attrs
  NFSD: set attributes when creating symlinks
  NFSD: introduce struct nfsd_attrs
  NFSD: verify the opened dentry after setting a delegation
  NFSD: drop fh argument from alloc_init_deleg
  NFSD: Move copy offload callback arguments into a separate structure
  NFSD: Add nfsd4_send_cb_offload()
  NFSD: Remove kmalloc from nfsd4_do_async_copy()
  NFSD: Refactor nfsd4_do_copy()
  NFSD: Refactor nfsd4_cleanup_inter_ssc() (2/2)
  NFSD: Refactor nfsd4_cleanup_inter_ssc() (1/2)
  ...
parents 15205c28 6930bcbf
......@@ -169,6 +169,13 @@ configuration of fault-injection capabilities.
default is 'N', setting it to 'Y' will disable disconnect
injection on the RPC server.
- /sys/kernel/debug/fail_sunrpc/ignore-cache-wait:
Format: { 'Y' | 'N' }
default is 'N', setting it to 'Y' will disable cache wait
injection on the RPC server.
- /sys/kernel/debug/fail_function/inject:
Format: { 'function-name' | '!function-name' | '' }
......
......@@ -32,6 +32,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
if (!nlmsvc_ops)
return nlm_lck_denied_nolocks;
if (lock->lock_start > OFFSET_MAX ||
(lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
return nlm4_fbig;
/* Obtain host handle */
if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
|| (argp->monitor && nsm_monitor(host) < 0))
......@@ -50,6 +54,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Set up the missing parts of the file_lock structure */
lock->fl.fl_file = file->f_file[mode];
lock->fl.fl_pid = current->tgid;
lock->fl.fl_start = (loff_t)lock->lock_start;
lock->fl.fl_end = lock->lock_len ?
(loff_t)(lock->lock_start + lock->lock_len - 1) :
OFFSET_MAX;
lock->fl.fl_lmops = &nlmsvc_lock_operations;
nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
if (!lock->fl.fl_owner) {
......@@ -87,6 +95,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_host *host;
struct nlm_file *file;
struct nlm_lockowner *test_owner;
__be32 rc = rpc_success;
dprintk("lockd: TEST4 called\n");
......@@ -96,6 +105,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
test_owner = argp->lock.fl.fl_owner;
/* Now check for conflicting locks */
resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
if (resp->status == nlm_drop_reply)
......@@ -103,7 +113,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
else
dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(&argp->lock);
nlmsvc_put_lockowner(test_owner);
nlmsvc_release_host(host);
nlm_release_file(file);
return rc;
......
......@@ -340,7 +340,7 @@ nlmsvc_get_lockowner(struct nlm_lockowner *lockowner)
return lockowner;
}
static void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner)
{
if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
return;
......@@ -590,7 +590,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
int error;
int mode;
__be32 ret;
struct nlm_lockowner *test_owner;
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
nlmsvc_file_inode(file)->i_sb->s_id,
......@@ -604,9 +603,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out;
}
/* If there's a conflicting lock, remember to clean up the test lock */
test_owner = (struct nlm_lockowner *)lock->fl.fl_owner;
mode = lock_to_openmode(&lock->fl);
error = vfs_test_lock(file->f_file[mode], &lock->fl);
if (error) {
......@@ -635,10 +631,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
conflock->fl.fl_end = lock->fl.fl_end;
locks_release_private(&lock->fl);
/* Clean up the test lock */
lock->fl.fl_owner = NULL;
nlmsvc_put_lockowner(test_owner);
ret = nlm_lck_denied;
out:
return ret;
......
......@@ -116,6 +116,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_host *host;
struct nlm_file *file;
struct nlm_lockowner *test_owner;
__be32 rc = rpc_success;
dprintk("lockd: TEST called\n");
......@@ -125,6 +126,8 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
test_owner = argp->lock.fl.fl_owner;
/* Now check for conflicting locks */
resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie));
if (resp->status == nlm_drop_reply)
......@@ -133,7 +136,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
dprintk("lockd: TEST status %d vers %d\n",
ntohl(resp->status), rqstp->rq_vers);
nlmsvc_release_lockowner(&argp->lock);
nlmsvc_put_lockowner(test_owner);
nlmsvc_release_host(host);
nlm_release_file(file);
return rc;
......
......@@ -20,13 +20,6 @@
#include "svcxdr.h"
static inline loff_t
s64_to_loff_t(__s64 offset)
{
return (loff_t)offset;
}
static inline s64
loff_t_to_s64(loff_t offset)
{
......@@ -70,8 +63,6 @@ static bool
svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
u64 len, start;
s64 end;
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
return false;
......@@ -81,20 +72,14 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
return false;
if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
return false;
if (xdr_stream_decode_u64(xdr, &start) < 0)
if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0)
return false;
if (xdr_stream_decode_u64(xdr, &len) < 0)
if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0)
return false;
locks_init_lock(fl);
fl->fl_flags = FL_POSIX;
fl->fl_type = F_RDLCK;
end = start + len - 1;
fl->fl_start = s64_to_loff_t(start);
if (len == 0 || end < 0)
fl->fl_end = OFFSET_MAX;
else
fl->fl_end = s64_to_loff_t(end);
return true;
}
......
......@@ -38,6 +38,8 @@
struct nfs4_acl;
struct svc_fh;
struct svc_rqst;
struct nfsd_attrs;
enum nfs_ftype4;
int nfs4_acl_bytes(int entries);
int nfs4_acl_get_whotype(char *, u32);
......@@ -45,7 +47,7 @@ __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
struct nfs4_acl **acl);
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfs4_acl *acl);
__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
struct nfsd_attrs *attr);
#endif /* LINUX_NFS4_ACL_H */
This diff is collapsed.
......@@ -29,7 +29,7 @@ struct nfsd_file_mark {
* never be dereferenced, only used for comparison.
*/
struct nfsd_file {
struct hlist_node nf_node;
struct rhash_head nf_rhash;
struct list_head nf_lru;
struct rcu_head nf_rcu;
struct file *nf_file;
......@@ -37,15 +37,13 @@ struct nfsd_file {
struct net *nf_net;
#define NFSD_FILE_HASHED (0)
#define NFSD_FILE_PENDING (1)
#define NFSD_FILE_BREAK_READ (2)
#define NFSD_FILE_BREAK_WRITE (3)
#define NFSD_FILE_REFERENCED (4)
#define NFSD_FILE_REFERENCED (2)
unsigned long nf_flags;
struct inode *nf_inode;
unsigned int nf_hashval;
struct inode *nf_inode; /* don't deref */
refcount_t nf_ref;
unsigned char nf_may;
struct nfsd_file_mark *nf_mark;
ktime_t nf_birthtime;
};
int nfsd_file_cache_init(void);
......@@ -54,6 +52,7 @@ void nfsd_file_cache_shutdown(void);
int nfsd_file_cache_start_net(struct net *net);
void nfsd_file_cache_shutdown_net(struct net *net);
void nfsd_file_put(struct nfsd_file *nf);
void nfsd_file_close(struct nfsd_file *nf);
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
void nfsd_file_close_inode_sync(struct inode *inode);
bool nfsd_file_is_cached(struct inode *inode);
......
......@@ -189,6 +189,9 @@ struct nfsd_net {
struct nfsd_fcache_disposal *fcache_disposal;
siphash_key_t siphash_key;
atomic_t nfs4_client_count;
int nfs4_max_clients;
};
/* Simple check to find out if a given net was properly initialized */
......
......@@ -111,7 +111,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
if (error)
goto out_errno;
fh_lock(fh);
inode_lock(inode);
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
argp->acl_access);
......@@ -122,7 +122,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
if (error)
goto out_drop_lock;
fh_unlock(fh);
inode_unlock(inode);
fh_drop_write(fh);
......@@ -136,7 +136,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
return rpc_success;
out_drop_lock:
fh_unlock(fh);
inode_unlock(inode);
fh_drop_write(fh);
out_errno:
resp->status = nfserrno(error);
......
......@@ -101,7 +101,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
if (error)
goto out_errno;
fh_lock(fh);
inode_lock(inode);
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
argp->acl_access);
......@@ -111,7 +111,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
argp->acl_default);
out_drop_lock:
fh_unlock(fh);
inode_unlock(inode);
fh_drop_write(fh);
out_errno:
resp->status = nfserrno(error);
......
......@@ -67,12 +67,15 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp)
{
struct nfsd3_sattrargs *argp = rqstp->rq_argp;
struct nfsd3_attrstat *resp = rqstp->rq_resp;
struct nfsd_attrs attrs = {
.na_iattr = &argp->attrs,
};
dprintk("nfsd: SETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs,
argp->check_guard, argp->guardtime);
return rpc_success;
}
......@@ -233,6 +236,9 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
{
struct iattr *iap = &argp->attrs;
struct dentry *parent, *child;
struct nfsd_attrs attrs = {
.na_iattr = iap,
};
__u32 v_mtime, v_atime;
struct inode *inode;
__be32 status;
......@@ -254,7 +260,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (host_err)
return nfserrno(host_err);
fh_lock_nested(fhp, I_MUTEX_PARENT);
inode_lock_nested(inode, I_MUTEX_PARENT);
child = lookup_one_len(argp->name, parent, argp->len);
if (IS_ERR(child)) {
......@@ -312,11 +318,13 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!IS_POSIXACL(inode))
iap->ia_mode &= ~current_umask();
fh_fill_pre_attrs(fhp);
host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
if (host_err < 0) {
status = nfserrno(host_err);
goto out;
}
fh_fill_post_attrs(fhp);
/* A newly created file already has a file size of zero. */
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
......@@ -331,10 +339,10 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
set_attr:
status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
out:
fh_unlock(fhp);
inode_unlock(inode);
if (child && !IS_ERR(child))
dput(child);
fh_drop_write(fhp);
......@@ -368,6 +376,9 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
{
struct nfsd3_createargs *argp = rqstp->rq_argp;
struct nfsd3_diropres *resp = rqstp->rq_resp;
struct nfsd_attrs attrs = {
.na_iattr = &argp->attrs,
};
dprintk("nfsd: MKDIR(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
......@@ -378,8 +389,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
fh_copy(&resp->dirfh, &argp->fh);
fh_init(&resp->fh, NFS3_FHSIZE);
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
fh_unlock(&resp->dirfh);
&attrs, S_IFDIR, 0, &resp->fh);
return rpc_success;
}
......@@ -388,6 +398,9 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
{
struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
struct nfsd3_diropres *resp = rqstp->rq_resp;
struct nfsd_attrs attrs = {
.na_iattr = &argp->attrs,
};
if (argp->tlen == 0) {
resp->status = nfserr_inval;
......@@ -414,7 +427,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
fh_copy(&resp->dirfh, &argp->ffh);
fh_init(&resp->fh, NFS3_FHSIZE);
resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
argp->flen, argp->tname, &resp->fh);
argp->flen, argp->tname, &attrs, &resp->fh);
kfree(argp->tname);
out:
return rpc_success;
......@@ -428,6 +441,9 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
{
struct nfsd3_mknodargs *argp = rqstp->rq_argp;
struct nfsd3_diropres *resp = rqstp->rq_resp;
struct nfsd_attrs attrs = {
.na_iattr = &argp->attrs,
};
int type;
dev_t rdev = 0;
......@@ -453,8 +469,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
type = nfs3_ftypes[argp->ftype];
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, type, rdev, &resp->fh);
fh_unlock(&resp->dirfh);
&attrs, type, rdev, &resp->fh);
out:
return rpc_success;
}
......@@ -477,7 +492,6 @@ nfsd3_proc_remove(struct svc_rqst *rqstp)
fh_copy(&resp->fh, &argp->fh);
resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
argp->name, argp->len);
fh_unlock(&resp->fh);
return rpc_success;
}
......@@ -498,7 +512,6 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp)
fh_copy(&resp->fh, &argp->fh);
resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
argp->name, argp->len);
fh_unlock(&resp->fh);
return rpc_success;
}
......
......@@ -751,58 +751,26 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
return ret;
}
__be32
nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfs4_acl *acl)
__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
struct nfsd_attrs *attr)
{
__be32 error;
int host_error;
struct dentry *dentry;
struct inode *inode;
struct posix_acl *pacl = NULL, *dpacl = NULL;
unsigned int flags = 0;
/* Get inode */
error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
if (error)
return error;
dentry = fhp->fh_dentry;
inode = d_inode(dentry);
if (!acl)
return nfs_ok;
if (S_ISDIR(inode->i_mode))
if (type == NF4DIR)
flags = NFS4_ACL_DIR;
host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->na_pacl,
&attr->na_dpacl, flags);
if (host_error == -EINVAL)
return nfserr_attrnotsupp;
if (host_error < 0)
goto out_nfserr;
fh_lock(fhp);
host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
if (host_error < 0)
goto out_drop_lock;
if (S_ISDIR(inode->i_mode)) {
host_error = set_posix_acl(&init_user_ns, inode,
ACL_TYPE_DEFAULT, dpacl);
}
out_drop_lock:
fh_unlock(fhp);
posix_acl_release(pacl);
posix_acl_release(dpacl);
out_nfserr:
if (host_error == -EOPNOTSUPP)
return nfserr_attrnotsupp;
else
return nfserrno(host_error);
}
static short
ace2type(struct nfs4_ace *ace)
{
......
......@@ -679,7 +679,7 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
* case NFS4_OK:
* write_response4 coa_resok4;
* default:
* length4 coa_bytes_copied;
* length4 coa_bytes_copied;
* };
* struct CB_OFFLOAD4args {
* nfs_fh4 coa_fh;
......@@ -688,21 +688,22 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,
* };
*/
static void encode_offload_info4(struct xdr_stream *xdr,
__be32 nfserr,
const struct nfsd4_copy *cp)
const struct nfsd4_cb_offload *cbo)
{
__be32 *p;
p = xdr_reserve_space(xdr, 4);
*p++ = nfserr;
if (!nfserr) {
*p = cbo->co_nfserr;
switch (cbo->co_nfserr) {
case nfs_ok:
p = xdr_reserve_space(xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE);
p = xdr_encode_empty_array(p);
p = xdr_encode_hyper(p, cp->cp_res.wr_bytes_written);
*p++ = cpu_to_be32(cp->cp_res.wr_stable_how);
p = xdr_encode_opaque_fixed(p, cp->cp_res.wr_verifier.data,
p = xdr_encode_hyper(p, cbo->co_res.wr_bytes_written);
*p++ = cpu_to_be32(cbo->co_res.wr_stable_how);
p = xdr_encode_opaque_fixed(p, cbo->co_res.wr_verifier.data,
NFS4_VERIFIER_SIZE);
} else {
break;
default:
p = xdr_reserve_space(xdr, 8);
/* We always return success if bytes were written */
p = xdr_encode_hyper(p, 0);
......@@ -710,18 +711,16 @@ static void encode_offload_info4(struct xdr_stream *xdr,
}
static void encode_cb_offload4args(struct xdr_stream *xdr,
__be32 nfserr,
const struct knfsd_fh *fh,
const struct nfsd4_copy *cp,
const struct nfsd4_cb_offload *cbo,
struct nfs4_cb_compound_hdr *hdr)
{
__be32 *p;
p = xdr_reserve_space(xdr, 4);
*p++ = cpu_to_be32(OP_CB_OFFLOAD);
encode_nfs_fh4(xdr, fh);
encode_stateid4(xdr, &cp->cp_res.cb_stateid);
encode_offload_info4(xdr, nfserr, cp);
*p = cpu_to_be32(OP_CB_OFFLOAD);
encode_nfs_fh4(xdr, &cbo->co_fh);
encode_stateid4(xdr, &cbo->co_res.cb_stateid);
encode_offload_info4(xdr, cbo);
hdr->nops++;
}
......@@ -731,8 +730,8 @@ static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req,
const void *data)
{
const struct nfsd4_callback *cb = data;
const struct nfsd4_copy *cp =
container_of(cb, struct nfsd4_copy, cp_cb);
const struct nfsd4_cb_offload *cbo =
container_of(cb, struct nfsd4_cb_offload, co_cb);
struct nfs4_cb_compound_hdr hdr = {
.ident = 0,
.minorversion = cb->cb_clp->cl_minorversion,
......@@ -740,7 +739,7 @@ static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req,
encode_cb_compound4args(xdr, &hdr);
encode_cb_sequence4args(xdr, cb, &hdr);
encode_cb_offload4args(xdr, cp->nfserr, &cp->fh, cp, &hdr);
encode_cb_offload4args(xdr, cbo, &hdr);
encode_cb_nops(&hdr);
}
......
This diff is collapsed.
......@@ -820,9 +820,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
swap(f2, fp->fi_fds[O_RDWR]);
spin_unlock(&fp->fi_lock);
if (f1)
nfsd_file_put(f1);
nfsd_file_close(f1);
if (f2)
nfsd_file_put(f2);
nfsd_file_close(f2);
}
}
......@@ -1131,7 +1131,6 @@ static void block_delegations(struct knfsd_fh *fh)
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
struct svc_fh *current_fh,
struct nfs4_clnt_odstate *odstate)
{
struct nfs4_delegation *dp;
......@@ -1141,7 +1140,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
n = atomic_long_inc_return(&num_delegations);
if (n < 0 || n > max_delegations)
goto out_dec;
if (delegation_blocked(&current_fh->fh_handle))
if (delegation_blocked(&fp->fi_fhandle))
goto out_dec;
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
if (dp == NULL)
......@@ -2053,11 +2052,16 @@ STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
* This type of memory management is somewhat inefficient, but we use it
* anyway since SETCLIENTID is not a common operation.
*/
static struct nfs4_client *alloc_client(struct xdr_netobj name)
static struct nfs4_client *alloc_client(struct xdr_netobj name,
struct nfsd_net *nn)
{
struct nfs4_client *clp;
int i;
if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) {
mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
return NULL;
}
clp = kmem_cache_zalloc(client_slab, GFP_KERNEL);
if (clp == NULL)
return NULL;
......@@ -2076,6 +2080,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
atomic_set(&clp->cl_rpc_users, 0);
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
clp->cl_state = NFSD4_ACTIVE;
atomic_inc(&nn->nfs4_client_count);
atomic_set(&clp->cl_delegs_in_recall, 0);
INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_openowners);
......@@ -2183,6 +2188,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
static void
__destroy_client(struct nfs4_client *clp)
{
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
int i;
struct nfs4_openowner *oo;
struct nfs4_delegation *dp;
......@@ -2226,6 +2232,7 @@ __destroy_client(struct nfs4_client *clp)
nfsd4_shutdown_callback(clp);
if (clp->cl_cb_conn.cb_xprt)
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
atomic_add_unless(&nn->nfs4_client_count, -1, 0);
free_client(clp);
wake_up_all(&expiry_wq);
}
......@@ -2564,7 +2571,7 @@ static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f)
static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f)
{
struct inode *inode = f->nf_inode;
struct inode *inode = file_inode(f->nf_file);
seq_printf(s, "superblock: \"%02x:%02x:%ld\"",
MAJOR(inode->i_sb->s_dev),
......@@ -2848,7 +2855,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct dentry *dentries[ARRAY_SIZE(client_files)];
clp = alloc_client(name);
clp = alloc_client(name, nn);
if (clp == NULL)
return NULL;
......@@ -4330,6 +4337,27 @@ nfsd4_init_slabs(void)
return -ENOMEM;
}
void nfsd4_init_leases_net(struct nfsd_net *nn)
{
struct sysinfo si;
u64 max_clients;
nn->nfsd4_lease = 90; /* default lease time */
nn->nfsd4_grace = 90;
nn->somebody_reclaimed = false;
nn->track_reclaim_completes = false;
nn->clverifier_counter = prandom_u32();
nn->clientid_base = prandom_u32();
nn->clientid_counter = nn->clientid_base + 1;
nn->s2s_cp_cl_id = nn->clientid_counter++;
atomic_set(&nn->nfs4_client_count, 0);
si_meminfo(&si);
max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024);
max_clients *= NFS4_CLIENTS_PER_GB;
nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
}
static void init_nfs4_replay(struct nfs4_replay *rp)
{
rp->rp_status = nfserr_serverfault;
......@@ -5032,11 +5060,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
.ia_valid = ATTR_SIZE,
.ia_size = 0,
};
struct nfsd_attrs attrs = {
.na_iattr = &iattr,
};
if (!open->op_truncate)
return 0;
if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
return nfserr_inval;
return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0);
return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0);
}
static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
......@@ -5104,6 +5135,7 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
goto out_put_access;
nf->nf_file = open->op_filp;
open->op_filp = NULL;
trace_nfsd_file_create(rqstp, access, nf);
}
spin_lock(&fp->fi_lock);
......@@ -5259,11 +5291,41 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
return 0;
}
/*
* It's possible that between opening the dentry and setting the delegation,
* that it has been renamed or unlinked. Redo the lookup to verify that this
* hasn't happened.
*/
static int
nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
struct svc_fh *parent)
{
struct svc_export *exp;
struct dentry *child;
__be32 err;
err = nfsd_lookup_dentry(open->op_rqstp, parent,
open->op_fname, open->op_fnamelen,
&exp, &child);
if (err)
return -EAGAIN;
dput(child);
if (child != file_dentry(fp->fi_deleg_file->nf_file))
return -EAGAIN;
return 0;
}
static struct nfs4_delegation *
nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
struct svc_fh *parent)
{
int status = 0;
struct nfs4_client *clp = stp->st_stid.sc_client;
struct nfs4_file *fp = stp->st_stid.sc_file;
struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
struct nfs4_delegation *dp;
struct nfsd_file *nf;
struct file_lock *fl;
......@@ -5305,7 +5367,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
return ERR_PTR(status);
status = -ENOMEM;
dp = alloc_init_deleg(clp, fp, fh, odstate);
dp = alloc_init_deleg(clp, fp, odstate);
if (!dp)
goto out_delegees;
......@@ -5318,6 +5380,13 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
locks_free_lock(fl);
if (status)
goto out_clnt_odstate;
if (parent) {
status = nfsd4_verify_deleg_dentry(open, fp, parent);
if (status)
goto out_unlock;
}
status = nfsd4_check_conflicting_opens(clp, fp);
if (status)
goto out_unlock;
......@@ -5373,12 +5442,13 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
* proper support for them.
*/
static void
nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
struct nfs4_ol_stateid *stp)
nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
struct svc_fh *currentfh)
{
struct nfs4_delegation *dp;
struct nfs4_openowner *oo = openowner(stp->st_stateowner);
struct nfs4_client *clp = stp->st_stid.sc_client;
struct svc_fh *parent = NULL;
int cb_up;
int status = 0;
......@@ -5392,6 +5462,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
goto out_no_deleg;
break;
case NFS4_OPEN_CLAIM_NULL:
parent = currentfh;
fallthrough;
case NFS4_OPEN_CLAIM_FH:
/*
* Let's not give out any delegations till everyone's
......@@ -5406,7 +5478,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
default:
goto out_no_deleg;
}
dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate);
dp = nfs4_set_delegation(open, stp, parent);
if (IS_ERR(dp))
goto out_no_deleg;
......@@ -5538,7 +5610,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
* Attempt to hand out a delegation. No error return, because the
* OPEN succeeds even if we fail.
*/
nfs4_open_delegation(current_fh, open, stp);
nfs4_open_delegation(open, stp, &resp->cstate.current_fh);
nodeleg:
status = nfs_ok;
trace_nfsd_open(&stp->st_stid.sc_stateid);
......@@ -5792,9 +5864,12 @@ static void
nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
struct laundry_time *lt)
{
unsigned int maxreap, reapcnt = 0;
struct list_head *pos, *next;
struct nfs4_client *clp;
maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ?
NFSD_CLIENT_MAX_TRIM_PER_RUN : 0;
INIT_LIST_HEAD(reaplist);
spin_lock(&nn->client_lock);
list_for_each_safe(pos, next, &nn->client_lru) {
......@@ -5805,14 +5880,15 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
break;
if (!atomic_read(&clp->cl_rpc_users))
clp->cl_state = NFSD4_COURTESY;
if (!client_has_state(clp) ||
ktime_get_boottime_seconds() >=
(clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT))
if (!client_has_state(clp))
goto exp_client;
if (nfs4_anylock_blockers(clp)) {
if (!nfs4_anylock_blockers(clp))
if (reapcnt >= maxreap)
continue;
exp_client:
if (!mark_client_expired_locked(clp))
list_add(&clp->cl_lru, reaplist);
if (!mark_client_expired_locked(clp)) {
list_add(&clp->cl_lru, reaplist);
reapcnt++;
}
}
spin_unlock(&nn->client_lock);
......@@ -7321,21 +7397,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
{
struct nfsd_file *nf;
struct inode *inode;
__be32 err;
err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf);
if (err)
return err;
fh_lock(fhp); /* to block new leases till after test_lock: */
err = nfserrno(nfsd_open_break_lease(fhp->fh_dentry->d_inode,
NFSD_MAY_READ));
inode = fhp->fh_dentry->d_inode;
inode_lock(inode); /* to block new leases till after test_lock: */
err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
if (err)
goto out;
lock->fl_file = nf->nf_file;
err = nfserrno(vfs_test_lock(nf->nf_file, lock));
lock->fl_file = NULL;
out:
fh_unlock(fhp);
inode_unlock(inode);
nfsd_file_put(nf);
return err;
}
......
......@@ -1810,7 +1810,7 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta
for (i = 0; i < test_stateid->ts_num_ids; i++) {
stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
if (!stateid)
return nfserrno(-ENOMEM); /* XXX: not jukebox? */
return nfserr_jukebox;
INIT_LIST_HEAD(&stateid->ts_id_list);
list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
status = nfsd4_decode_stateid4(argp, &stateid->ts_id_stateid);
......@@ -1896,8 +1896,8 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
{
u32 consecutive, i, count, sync;
struct nl4_server *ns_dummy;
u32 consecutive, i, count;
__be32 status;
status = nfsd4_decode_stateid4(argp, &copy->cp_src_stateid);
......@@ -1915,25 +1915,28 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
/* ca_consecutive: we always do consecutive copies */
if (xdr_stream_decode_u32(argp->xdr, &consecutive) < 0)
return nfserr_bad_xdr;
if (xdr_stream_decode_u32(argp->xdr, &copy->cp_synchronous) < 0)
if (xdr_stream_decode_bool(argp->xdr, &sync) < 0)
return nfserr_bad_xdr;
nfsd4_copy_set_sync(copy, sync);
if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
return nfserr_bad_xdr;
copy->cp_intra = false;
copy->cp_src = svcxdr_tmpalloc(argp, sizeof(*copy->cp_src));
if (copy->cp_src == NULL)
return nfserr_jukebox;
if (count == 0) { /* intra-server copy */
copy->cp_intra = true;
__set_bit(NFSD4_COPY_F_INTRA, &copy->cp_flags);
return nfs_ok;
}
/* decode all the supplied server addresses but use only the first */
status = nfsd4_decode_nl4_server(argp, &copy->cp_src);
status = nfsd4_decode_nl4_server(argp, copy->cp_src);
if (status)
return status;
ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL);
if (ns_dummy == NULL)
return nfserrno(-ENOMEM); /* XXX: jukebox? */
return nfserr_jukebox;
for (i = 0; i < count - 1; i++) {
status = nfsd4_decode_nl4_server(argp, ns_dummy);
if (status) {
......@@ -1952,10 +1955,17 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
{
__be32 status;
cn->cpn_src = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_src));
if (cn->cpn_src == NULL)
return nfserr_jukebox;
cn->cpn_dst = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_dst));
if (cn->cpn_dst == NULL)
return nfserr_jukebox;
status = nfsd4_decode_stateid4(argp, &cn->cpn_src_stateid);
if (status)
return status;
return nfsd4_decode_nl4_server(argp, &cn->cpn_dst);
return nfsd4_decode_nl4_server(argp, cn->cpn_dst);
}
static __be32
......@@ -2828,10 +2838,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
struct kstat stat;
struct svc_fh *tempfh = NULL;
struct kstatfs statfs;
__be32 *p;
__be32 *p, *attrlen_p;
int starting_len = xdr->buf->len;
int attrlen_offset;
__be32 attrlen;
u32 dummy;
u64 dummy64;
u32 rdattr_err = 0;
......@@ -2919,10 +2928,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
goto out;
attrlen_offset = xdr->buf->len;
p = xdr_reserve_space(xdr, 4);
if (!p)
attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
if (!attrlen_p)
goto out_resource;
p++; /* to be backfilled later */
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
u32 supp[3];
......@@ -3344,8 +3352,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
*p++ = cpu_to_be32(err == 0);
}
attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
*attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT);
status = nfs_ok;
out:
......@@ -3882,16 +3889,15 @@ static __be32 nfsd4_encode_splice_read(
struct xdr_stream *xdr = resp->xdr;
struct xdr_buf *buf = xdr->buf;
int status, space_left;
u32 eof;
__be32 nfserr;
__be32 *p = xdr->p - 2;
/* Make sure there will be room for padding if needed */
if (xdr->end - xdr->p < 1)
return nfserr_resource;
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
file, read->rd_offset, &maxcount, &eof);
file, read->rd_offset, &maxcount,
&read->rd_eof);
read->rd_length = maxcount;
if (nfserr)
goto out_err;
......@@ -3902,9 +3908,6 @@ static __be32 nfsd4_encode_splice_read(
goto out_err;
}
*(p++) = htonl(eof);
*(p++) = htonl(maxcount);
buf->page_len = maxcount;
buf->len += maxcount;
xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
......@@ -3946,11 +3949,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
struct file *file, unsigned long maxcount)
{
struct xdr_stream *xdr = resp->xdr;
u32 eof;
int starting_len = xdr->buf->len - 8;
unsigned int starting_len = xdr->buf->len;
__be32 zero = xdr_zero;
__be32 nfserr;
__be32 tmp;
int pad;
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount);
if (read->rd_vlen < 0)
......@@ -3958,31 +3959,24 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
&eof);
&read->rd_eof);
read->rd_length = maxcount;
if (nfserr)
return nfserr;
if (svc_encode_result_payload(resp->rqstp, starting_len + 8, maxcount))
if (svc_encode_result_payload(resp->rqstp, starting_len, maxcount))
return nfserr_io;
xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount));
tmp = htonl(eof);
write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
tmp = htonl(maxcount);
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
tmp = xdr_zero;
pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
&tmp, pad);
return 0;
xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount));
write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &zero,
xdr_pad_size(maxcount));
return nfs_ok;
}
static __be32
nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_read *read)
{
bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
unsigned long maxcount;
struct xdr_stream *xdr = resp->xdr;
struct file *file;
......@@ -3995,11 +3989,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
if (!p) {
WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
WARN_ON_ONCE(splice_ok);
return nfserr_resource;
}
if (resp->xdr->buf->page_len &&
test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
if (resp->xdr->buf->page_len && splice_ok) {
WARN_ON_ONCE(1);
return nfserr_resource;
}
......@@ -4008,31 +4001,30 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
maxcount = min_t(unsigned long, read->rd_length,
(xdr->buf->buflen - xdr->buf->len));
if (file->f_op->splice_read &&
test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
if (file->f_op->splice_read && splice_ok)
nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
else
nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
if (nfserr)
if (nfserr) {
xdr_truncate_encode(xdr, starting_len);
return nfserr;
}
return nfserr;
p = xdr_encode_bool(p, read->rd_eof);
*p = cpu_to_be32(read->rd_length);
return nfs_ok;
}
static __be32
nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
{
int maxcount;
__be32 wire_count;
int zero = 0;
__be32 *p, *maxcount_p, zero = xdr_zero;
struct xdr_stream *xdr = resp->xdr;
int length_offset = xdr->buf->len;
int status;
__be32 *p;
int maxcount, status;
p = xdr_reserve_space(xdr, 4);
if (!p)
maxcount_p = xdr_reserve_space(xdr, XDR_UNIT);
if (!maxcount_p)
return nfserr_resource;
maxcount = PAGE_SIZE;
......@@ -4057,14 +4049,11 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
nfserr = nfserrno(status);
goto out_err;
}
wire_count = htonl(maxcount);
write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4));
if (maxcount & 3)
write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
&zero, 4 - (maxcount&3));
return 0;
*maxcount_p = cpu_to_be32(maxcount);
xdr_truncate_encode(xdr, length_offset + 4 + xdr_align_size(maxcount));
write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, &zero,
xdr_pad_size(maxcount));
return nfs_ok;
out_err:
xdr_truncate_encode(xdr, length_offset);
......@@ -4715,13 +4704,13 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
__be32 *p;
nfserr = nfsd42_encode_write_res(resp, &copy->cp_res,
!!copy->cp_synchronous);
nfsd4_copy_is_sync(copy));
if (nfserr)
return nfserr;
p = xdr_reserve_space(resp->xdr, 4 + 4);
*p++ = xdr_one; /* cr_consecutive */
*p++ = cpu_to_be32(copy->cp_synchronous);
*p = nfsd4_copy_is_sync(copy) ? xdr_one : xdr_zero;
return 0;
}
......@@ -4919,7 +4908,8 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
*p++ = cpu_to_be32(1);
return nfsd42_encode_nl4_server(resp, &cn->cpn_src);
nfserr = nfsd42_encode_nl4_server(resp, cn->cpn_src);
return nfserr;
}
static __be32
......@@ -5373,8 +5363,7 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
so->so_replay.rp_buf, len);
}
status:
/* Note that op->status is already in network byte order: */
write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
*p = op->status;
}
/*
......
......@@ -25,6 +25,7 @@
#include "state.h"
#include "netns.h"
#include "pnfs.h"
#include "filecache.h"
/*
* We have a single directory with several nodes in it.
......@@ -45,6 +46,7 @@ enum {
NFSD_Ports,
NFSD_MaxBlkSize,
NFSD_MaxConnections,
NFSD_Filecache,
NFSD_SupportedEnctypes,
/*
* The below MUST come last. Otherwise we leave a hole in nfsd_files[]
......@@ -229,6 +231,13 @@ static const struct file_operations reply_cache_stats_operations = {
.release = single_release,
};
static const struct file_operations filecache_ops = {
.open = nfsd_file_cache_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*----------------------------------------------------------------------------*/
/*
* payload - write methods
......@@ -633,7 +642,6 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
}
/* Now write current state into reply buffer */
len = 0;
sep = "";
remaining = SIMPLE_TRANSACTION_LIMIT;
for (num=2 ; num <= 4 ; num++) {
......@@ -1371,6 +1379,7 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_Filecache] = {"filecache", &filecache_ops, S_IRUGO},
#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
[NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
......@@ -1475,14 +1484,7 @@ static __net_init int nfsd_init_net(struct net *net)
retval = nfsd_reply_cache_init(nn);
if (retval)
goto out_drc_error;
nn->nfsd4_lease = 90; /* default lease time */
nn->nfsd4_grace = 90;
nn->somebody_reclaimed = false;
nn->track_reclaim_completes = false;
nn->clverifier_counter = prandom_u32();
nn->clientid_base = prandom_u32();
nn->clientid_counter = nn->clientid_base + 1;
nn->s2s_cp_cl_id = nn->clientid_counter++;
nfsd4_init_leases_net(nn);
get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
seqlock_init(&nn->writeverf_lock);
......@@ -1517,7 +1519,6 @@ static struct pernet_operations nfsd_net_ops = {
static int __init init_nfsd(void)
{
int retval;
printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
retval = nfsd4_init_slabs();
if (retval)
......
......@@ -341,6 +341,8 @@ void nfsd_lockd_shutdown(void);
#define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */
#define NFSD_COURTESY_CLIENT_TIMEOUT (24 * 60 * 60) /* seconds */
#define NFSD_CLIENT_MAX_TRIM_PER_RUN 128
#define NFS4_CLIENTS_PER_GB 1024
/*
* The following attributes are currently not supported by the NFSv4 server:
......@@ -496,12 +498,16 @@ extern void unregister_cld_notifier(void);
extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
#endif
extern void nfsd4_init_leases_net(struct nfsd_net *nn);
#else /* CONFIG_NFSD_V4 */
static inline int nfsd4_is_junction(struct dentry *dentry)
{
return 0;
}
static inline void nfsd4_init_leases_net(struct nfsd_net *nn) {};
#define register_cld_notifier() 0
#define unregister_cld_notifier() do { } while(0)
......
......@@ -331,8 +331,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
struct dentry *dentry;
__be32 error;
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
if (!fhp->fh_dentry) {
error = nfsd_set_fh_dentry(rqstp, fhp);
if (error)
......@@ -340,6 +338,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
}
dentry = fhp->fh_dentry;
exp = fhp->fh_export;
trace_nfsd_fh_verify(rqstp, fhp, type, access);
/*
* We still have to do all these permission checks, even when
* fh_dentry is already set:
......@@ -548,7 +549,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
if (ref_fh == fhp)
fh_put(ref_fh);
if (fhp->fh_locked || fhp->fh_dentry) {
if (fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n",
dentry);
}
......@@ -671,6 +672,25 @@ void fh_fill_post_attrs(struct svc_fh *fhp)
nfsd4_change_attribute(&fhp->fh_post_attr, inode);
}
/**
* fh_fill_both_attrs - Fill pre-op and post-op attributes
* @fhp: file handle to be updated
*
* This is used when the directory wasn't changed, but wcc attributes
* are needed anyway.
*/
void fh_fill_both_attrs(struct svc_fh *fhp)
{
fh_fill_post_attrs(fhp);
if (!fhp->fh_post_saved)
return;
fhp->fh_pre_change = fhp->fh_post_change;
fhp->fh_pre_mtime = fhp->fh_post_attr.mtime;
fhp->fh_pre_ctime = fhp->fh_post_attr.ctime;
fhp->fh_pre_size = fhp->fh_post_attr.size;
fhp->fh_pre_saved = true;
}
/*
* Release a file handle.
*/
......@@ -680,7 +700,6 @@ fh_put(struct svc_fh *fhp)
struct dentry * dentry = fhp->fh_dentry;
struct svc_export * exp = fhp->fh_export;
if (dentry) {
fh_unlock(fhp);
fhp->fh_dentry = NULL;
dput(dentry);
fh_clear_pre_post_attrs(fhp);
......
......@@ -81,7 +81,6 @@ typedef struct svc_fh {
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
bool fh_locked; /* inode locked by us */
bool fh_want_write; /* remount protection taken */
bool fh_no_wcc; /* no wcc data needed */
bool fh_no_atomic_attr;
......@@ -93,7 +92,7 @@ typedef struct svc_fh {
bool fh_post_saved; /* post-op attrs saved */
bool fh_pre_saved; /* pre-op attrs saved */
/* Pre-op attributes saved during fh_lock */
/* Pre-op attributes saved when inode is locked */
__u64 fh_pre_size; /* size before operation */
struct timespec64 fh_pre_mtime; /* mtime before oper */
struct timespec64 fh_pre_ctime; /* ctime before oper */
......@@ -103,7 +102,7 @@ typedef struct svc_fh {
*/
u64 fh_pre_change;
/* Post-op attributes saved in fh_unlock */
/* Post-op attributes saved in fh_fill_post_attrs() */
struct kstat fh_post_attr; /* full attrs after operation */
u64 fh_post_change; /* nfsv4 change; see above */
} svc_fh;
......@@ -223,8 +222,8 @@ void fh_put(struct svc_fh *);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
WARN_ON(src->fh_dentry || src->fh_locked);
WARN_ON(src->fh_dentry);
*dst = *src;
return dst;
}
......@@ -322,52 +321,5 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
extern void fh_fill_pre_attrs(struct svc_fh *fhp);
extern void fh_fill_post_attrs(struct svc_fh *fhp);
/*
* Lock a file handle/inode
* NOTE: both fh_lock and fh_unlock are done "by hand" in
* vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
* so, any changes here should be reflected there.
*/
static inline void
fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
{
struct dentry *dentry = fhp->fh_dentry;
struct inode *inode;
BUG_ON(!dentry);
if (fhp->fh_locked) {
printk(KERN_WARNING "fh_lock: %pd2 already locked!\n",
dentry);
return;
}
inode = d_inode(dentry);
inode_lock_nested(inode, subclass);
fh_fill_pre_attrs(fhp);
fhp->fh_locked = true;
}
static inline void
fh_lock(struct svc_fh *fhp)
{
fh_lock_nested(fhp, I_MUTEX_NORMAL);
}
/*
* Unlock a file handle/inode
*/
static inline void
fh_unlock(struct svc_fh *fhp)
{
if (fhp->fh_locked) {
fh_fill_post_attrs(fhp);
inode_unlock(d_inode(fhp->fh_dentry));
fhp->fh_locked = false;
}
}
extern void fh_fill_both_attrs(struct svc_fh *fhp);
#endif /* _LINUX_NFSD_NFSFH_H */
......@@ -51,6 +51,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
struct nfsd_sattrargs *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp;
struct iattr *iap = &argp->attrs;
struct nfsd_attrs attrs = {
.na_iattr = iap,
};
struct svc_fh *fhp;
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
......@@ -100,7 +103,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
}
}
resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0);
if (resp->status != nfs_ok)
goto out;
......@@ -260,6 +263,9 @@ nfsd_proc_create(struct svc_rqst *rqstp)
svc_fh *dirfhp = &argp->fh;
svc_fh *newfhp = &resp->fh;
struct iattr *attr = &argp->attrs;
struct nfsd_attrs attrs = {
.na_iattr = attr,
};
struct inode *inode;
struct dentry *dchild;
int type, mode;
......@@ -285,7 +291,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
goto done;
}
fh_lock_nested(dirfhp, I_MUTEX_PARENT);
inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
if (IS_ERR(dchild)) {
resp->status = nfserrno(PTR_ERR(dchild));
......@@ -385,7 +391,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
if (!inode) {
/* File doesn't exist. Create it and set attrs */
resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
argp->len, attr, type, rdev,
argp->len, &attrs, type, rdev,
newfhp);
} else if (type == S_IFREG) {
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
......@@ -396,13 +402,12 @@ nfsd_proc_create(struct svc_rqst *rqstp)
*/
attr->ia_valid &= ATTR_SIZE;
if (attr->ia_valid)
resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0,
(time64_t)0);
}
out_unlock:
/* We don't really need to unlock, as fh_put does it. */
fh_unlock(dirfhp);
inode_unlock(dirfhp->fh_dentry->d_inode);
fh_drop_write(dirfhp);
done:
fh_put(dirfhp);
......@@ -472,6 +477,9 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
{
struct nfsd_symlinkargs *argp = rqstp->rq_argp;
struct nfsd_stat *resp = rqstp->rq_resp;
struct nfsd_attrs attrs = {
.na_iattr = &argp->attrs,
};
struct svc_fh newfh;
if (argp->tlen > NFS_MAXPATHLEN) {
......@@ -493,7 +501,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
fh_init(&newfh, NFS_FHSIZE);
resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
argp->tname, &newfh);
argp->tname, &attrs, &newfh);
kfree(argp->tname);
fh_put(&argp->ffh);
......@@ -511,6 +519,9 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
{
struct nfsd_createargs *argp = rqstp->rq_argp;
struct nfsd_diropres *resp = rqstp->rq_resp;
struct nfsd_attrs attrs = {
.na_iattr = &argp->attrs,
};
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
......@@ -522,7 +533,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
argp->attrs.ia_valid &= ~ATTR_SIZE;
fh_init(&resp->fh, NFS_FHSIZE);
resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
&attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
if (resp->status != nfs_ok)
goto out;
......
......@@ -703,7 +703,6 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
void put_nfs4_file(struct nfs4_file *fi);
extern void nfs4_put_copy(struct nfsd4_copy *copy);
extern struct nfsd4_copy *
find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,8 @@
#ifndef LINUX_NFSD_VFS_H
#define LINUX_NFSD_VFS_H
#include <linux/fs.h>
#include <linux/posix_acl.h>
#include "nfsfh.h"
#include "nfsd.h"
......@@ -42,6 +44,22 @@ struct nfsd_file;
typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
/* nfsd/vfs.c */
struct nfsd_attrs {
struct iattr *na_iattr; /* input */
struct xdr_netobj *na_seclabel; /* input */
struct posix_acl *na_pacl; /* input */
struct posix_acl *na_dpacl; /* input */
int na_labelerr; /* output */
int na_aclerr; /* output */
};
static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
{
posix_acl_release(attrs->na_pacl);
posix_acl_release(attrs->na_dpacl);
}
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp);
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
......@@ -50,11 +68,9 @@ __be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
const char *, unsigned int,
struct svc_export **, struct dentry **);
__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *, int, time64_t);
struct nfsd_attrs *, int, time64_t);
int nfsd_mountpoint(struct dentry *, struct svc_export *);
#ifdef CONFIG_NFSD_V4
__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
struct xdr_netobj *);
__be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
struct file *, loff_t, loff_t, int);
__be32 nfsd4_clone_file_range(struct svc_rqst *rqstp,
......@@ -63,14 +79,14 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp,
u64 count, bool sync);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
char *name, int len, struct nfsd_attrs *attrs,
int type, dev_t rdev, struct svc_fh *res);
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
char *name, int len, struct nfsd_attrs *attrs,
int type, dev_t rdev, struct svc_fh *res);
__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
__be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct svc_fh *resfhp, struct iattr *iap);
struct svc_fh *resfhp, struct nfsd_attrs *iap);
__be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
u64 offset, u32 count, __be32 *verf);
#ifdef CONFIG_NFSD_V4
......@@ -110,8 +126,9 @@ __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *);
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
char *name, int len, char *path,
struct svc_fh *res);
char *name, int len, char *path,
struct nfsd_attrs *attrs,
struct svc_fh *res);
__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
char *, int, struct svc_fh *);
ssize_t nfsd_copy_file_range(struct file *, u64,
......
......@@ -279,6 +279,7 @@ struct nfsd4_open {
struct nfs4_clnt_odstate *op_odstate; /* used during processing */
struct nfs4_acl *op_acl;
struct xdr_netobj op_label;
struct svc_rqst *op_rqstp;
};
struct nfsd4_open_confirm {
......@@ -302,9 +303,10 @@ struct nfsd4_read {
u32 rd_length; /* request */
int rd_vlen;
struct nfsd_file *rd_nf;
struct svc_rqst *rd_rqstp; /* response */
struct svc_fh *rd_fhp; /* response */
struct svc_fh *rd_fhp; /* response */
u32 rd_eof; /* response */
};
struct nfsd4_readdir {
......@@ -532,6 +534,13 @@ struct nfsd42_write_res {
stateid_t cb_stateid;
};
struct nfsd4_cb_offload {
struct nfsd4_callback co_cb;
struct nfsd42_write_res co_res;
__be32 co_nfserr;
struct knfsd_fh co_fh;
};
struct nfsd4_copy {
/* request */
stateid_t cp_src_stateid;
......@@ -539,18 +548,16 @@ struct nfsd4_copy {
u64 cp_src_pos;
u64 cp_dst_pos;
u64 cp_count;
struct nl4_server cp_src;
bool cp_intra;
struct nl4_server *cp_src;
/* both */
u32 cp_synchronous;
unsigned long cp_flags;
#define NFSD4_COPY_F_STOPPED (0)
#define NFSD4_COPY_F_INTRA (1)
#define NFSD4_COPY_F_SYNCHRONOUS (2)
#define NFSD4_COPY_F_COMMITTED (3)
/* response */
struct nfsd42_write_res cp_res;
/* for cb_offload */
struct nfsd4_callback cp_cb;
__be32 nfserr;
struct knfsd_fh fh;
struct nfs4_client *cp_clp;
......@@ -563,14 +570,35 @@ struct nfsd4_copy {
struct list_head copies;
struct task_struct *copy_task;
refcount_t refcount;
bool stopped;
struct vfsmount *ss_mnt;
struct nfs_fh c_fh;
nfs4_stateid stateid;
bool committed;
};
static inline void nfsd4_copy_set_sync(struct nfsd4_copy *copy, bool sync)
{
if (sync)
set_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
else
clear_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
}
static inline bool nfsd4_copy_is_sync(const struct nfsd4_copy *copy)
{
return test_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
}
static inline bool nfsd4_copy_is_async(const struct nfsd4_copy *copy)
{
return !test_bit(NFSD4_COPY_F_SYNCHRONOUS, &copy->cp_flags);
}
static inline bool nfsd4_ssc_is_inter(const struct nfsd4_copy *copy)
{
return !test_bit(NFSD4_COPY_F_INTRA, &copy->cp_flags);
}
struct nfsd4_seek {
/* request */
stateid_t seek_stateid;
......@@ -594,19 +622,20 @@ struct nfsd4_offload_status {
struct nfsd4_copy_notify {
/* request */
stateid_t cpn_src_stateid;
struct nl4_server cpn_dst;
struct nl4_server *cpn_dst;
/* response */
stateid_t cpn_cnr_stateid;
u64 cpn_sec;
u32 cpn_nsec;
struct nl4_server cpn_src;
struct nl4_server *cpn_src;
};
struct nfsd4_op {
u32 opnum;
const struct nfsd4_operation * opdesc;
__be32 status;
const struct nfsd4_operation *opdesc;
struct nfs4_replay *replay;
union nfsd4_op_u {
struct nfsd4_access access;
struct nfsd4_close close;
......@@ -670,7 +699,6 @@ struct nfsd4_op {
struct nfsd4_listxattrs listxattrs;
struct nfsd4_removexattr removexattr;
} u;
struct nfs4_replay * replay;
};
bool nfsd4_cache_this_op(struct nfsd4_op *);
......
......@@ -292,6 +292,7 @@ void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t);
__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
struct nlm_lock *);
void nlm_release_file(struct nlm_file *);
void nlmsvc_put_lockowner(struct nlm_lockowner *);
void nlmsvc_release_lockowner(struct nlm_lock *);
void nlmsvc_mark_resources(struct net *);
void nlmsvc_free_host_resources(struct nlm_host *);
......
......@@ -41,6 +41,8 @@ struct nlm_lock {
struct nfs_fh fh;
struct xdr_netobj oh;
u32 svid;
u64 lock_start;
u64 lock_len;
struct file_lock fl;
};
......
......@@ -64,7 +64,7 @@ struct nfsd4_ssc_umount_item {
refcount_t nsui_refcnt;
unsigned long nsui_expire;
struct vfsmount *nsui_vfsmount;
char nsui_ipaddr[RPC_MAX_ADDRBUFLEN];
char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1];
};
#endif
......
......@@ -419,8 +419,8 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr)
*/
static inline __be32 *xdr_encode_bool(__be32 *p, u32 n)
{
*p = n ? xdr_one : xdr_zero;
return p++;
*p++ = n ? xdr_one : xdr_zero;
return p;
}
/**
......
......@@ -1989,20 +1989,24 @@ TRACE_EVENT(svc_wake_up,
TRACE_EVENT(svc_alloc_arg_err,
TP_PROTO(
unsigned int pages
unsigned int requested,
unsigned int allocated
),
TP_ARGS(pages),
TP_ARGS(requested, allocated),
TP_STRUCT__entry(
__field(unsigned int, pages)
__field(unsigned int, requested)
__field(unsigned int, allocated)
),
TP_fast_assign(
__entry->pages = pages;
__entry->requested = requested;
__entry->allocated = allocated;
),
TP_printk("pages=%u", __entry->pages)
TP_printk("requested=%u allocated=%u",
__entry->requested, __entry->allocated)
);
DECLARE_EVENT_CLASS(svc_deferred_event,
......
......@@ -691,7 +691,7 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
set_current_state(TASK_RUNNING);
return -EINTR;
}
trace_svc_alloc_arg_err(pages);
trace_svc_alloc_arg_err(pages, ret);
memalloc_retry_wait(GFP_KERNEL);
}
rqstp->rq_page_end = &rqstp->rq_pages[pages];
......
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