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