提交 965181d7 编写于 作者: L Linus Torvalds

Merge tag 'nfs-for-5.18-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client updates from Trond Myklebust:
 "Highlights include:

  Features:

   - Switch NFS to use readahead instead of the obsolete readpages.

   - Readdir fixes to improve cacheability of large directories when
     there are multiple readers and writers.

   - Readdir performance improvements when doing a seekdir() immediately
     after opening the directory (common when re-exporting NFS).

   - NFS swap improvements from Neil Brown.

   - Loosen up memory allocation to permit direct reclaim and write back
     in cases where there is no danger of deadlocking the writeback code
     or NFS swap.

   - Avoid sillyrename when the NFSv4 server claims to support the
     necessary features to recover the unlinked but open file after
     reboot.

  Bugfixes:

   - Patch from Olga to add a mount option to control NFSv4.1 session
     trunking discovery, and default it to being off.

   - Fix a lockup in nfs_do_recoalesce().

   - Two fixes for list iterator variables being used when pointing to
     the list head.

   - Fix a kernel memory scribble when reading from a non-socket
     transport in /sys/kernel/sunrpc.

   - Fix a race where reconnecting to a server could leave the TCP
     socket stuck forever in the connecting state.

   - Patch from Neil to fix a shutdown race which can leave the SUNRPC
     transport timer primed after we free the struct xprt itself.

   - Patch from Xin Xiong to fix reference count leaks in the NFSv4.2
     copy offload.

   - Sunrpc patch from Olga to avoid resending a task on an offlined
     transport.

  Cleanups:

   - Patches from Dave Wysochanski to clean up the fscache code"

* tag 'nfs-for-5.18-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (91 commits)
  NFSv4/pNFS: Fix another issue with a list iterator pointing to the head
  NFS: Don't loop forever in nfs_do_recoalesce()
  SUNRPC: Don't return error values in sysfs read of closed files
  SUNRPC: Do not dereference non-socket transports in sysfs
  NFSv4.1: don't retry BIND_CONN_TO_SESSION on session error
  SUNRPC don't resend a task on an offlined transport
  NFS: replace usage of found with dedicated list iterator variable
  SUNRPC: avoid race between mod_timer() and del_timer_sync()
  pNFS/files: Ensure pNFS allocation modes are consistent with nfsiod
  pNFS/flexfiles: Ensure pNFS allocation modes are consistent with nfsiod
  NFSv4/pnfs: Ensure pNFS allocation modes are consistent with nfsiod
  NFS: Avoid writeback threads getting stuck in mempool_alloc()
  NFS: nfsiod should not block forever in mempool_alloc()
  SUNRPC: Make the rpciod and xprtiod slab allocation modes consistent
  SUNRPC: Fix unx_lookup_cred() allocation
  NFS: Fix memory allocation in rpc_alloc_task()
  NFS: Fix memory allocation in rpc_malloc()
  SUNRPC: Improve accuracy of socket ENOBUFS determination
  SUNRPC: Replace internal use of SOCKWQ_ASYNC_NOSPACE
  SUNRPC: Fix socket waits for write buffer space
  ...
...@@ -4,6 +4,10 @@ config NFS_FS ...@@ -4,6 +4,10 @@ config NFS_FS
depends on INET && FILE_LOCKING && MULTIUSER depends on INET && FILE_LOCKING && MULTIUSER
select LOCKD select LOCKD
select SUNRPC select SUNRPC
select CRYPTO
select CRYPTO_HASH
select XXHASH
select CRYPTO_XXHASH
select NFS_ACL_SUPPORT if NFS_V3_ACL select NFS_ACL_SUPPORT if NFS_V3_ACL
help help
Choose Y here if you want to access files residing on other Choose Y here if you want to access files residing on other
......
...@@ -358,12 +358,11 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp, ...@@ -358,12 +358,11 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
struct cb_process_state *cps) struct cb_process_state *cps)
{ {
struct cb_devicenotifyargs *args = argp; struct cb_devicenotifyargs *args = argp;
const struct pnfs_layoutdriver_type *ld = NULL;
uint32_t i; uint32_t i;
__be32 res = 0; __be32 res = 0;
struct nfs_client *clp = cps->clp;
struct nfs_server *server = NULL;
if (!clp) { if (!cps->clp) {
res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION); res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
goto out; goto out;
} }
...@@ -371,23 +370,15 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp, ...@@ -371,23 +370,15 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
for (i = 0; i < args->ndevs; i++) { for (i = 0; i < args->ndevs; i++) {
struct cb_devicenotifyitem *dev = &args->devs[i]; struct cb_devicenotifyitem *dev = &args->devs[i];
if (!server || if (!ld || ld->id != dev->cbd_layout_type) {
server->pnfs_curr_ld->id != dev->cbd_layout_type) { pnfs_put_layoutdriver(ld);
rcu_read_lock(); ld = pnfs_find_layoutdriver(dev->cbd_layout_type);
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) if (!ld)
if (server->pnfs_curr_ld &&
server->pnfs_curr_ld->id == dev->cbd_layout_type) {
rcu_read_unlock();
goto found;
}
rcu_read_unlock();
continue; continue;
} }
nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id);
found:
nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
} }
pnfs_put_layoutdriver(ld);
out: out:
kfree(args->devs); kfree(args->devs);
return res; return res;
...@@ -710,7 +701,7 @@ __be32 nfs4_callback_offload(void *data, void *dummy, ...@@ -710,7 +701,7 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
struct nfs4_copy_state *copy, *tmp_copy; struct nfs4_copy_state *copy, *tmp_copy;
bool found = false; bool found = false;
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL);
if (!copy) if (!copy)
return htonl(NFS4ERR_SERVERFAULT); return htonl(NFS4ERR_SERVERFAULT);
......
...@@ -271,10 +271,6 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, ...@@ -271,10 +271,6 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
n = ntohl(*p++); n = ntohl(*p++);
if (n == 0) if (n == 0)
goto out; goto out;
if (n > ULONG_MAX / sizeof(*args->devs)) {
status = htonl(NFS4ERR_BADXDR);
goto out;
}
args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL);
if (!args->devs) { if (!args->devs) {
......
...@@ -857,7 +857,8 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str ...@@ -857,7 +857,8 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
} }
if (clp->rpc_ops->discover_trunking != NULL && if (clp->rpc_ops->discover_trunking != NULL &&
(server->caps & NFS_CAP_FS_LOCATIONS)) { (server->caps & NFS_CAP_FS_LOCATIONS &&
(server->flags & NFS_MOUNT_TRUNK_DISCOVERY))) {
error = clp->rpc_ops->discover_trunking(server, mntfh); error = clp->rpc_ops->discover_trunking(server, mntfh);
if (error < 0) if (error < 0)
return error; return error;
......
...@@ -439,7 +439,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, ...@@ -439,7 +439,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
struct nfs_delegation *freeme = NULL; struct nfs_delegation *freeme = NULL;
int status = 0; int status = 0;
delegation = kmalloc(sizeof(*delegation), GFP_NOFS); delegation = kmalloc(sizeof(*delegation), GFP_KERNEL_ACCOUNT);
if (delegation == NULL) if (delegation == NULL)
return -ENOMEM; return -ENOMEM;
nfs4_stateid_copy(&delegation->stateid, stateid); nfs4_stateid_copy(&delegation->stateid, stateid);
......
此差异已折叠。
...@@ -173,8 +173,8 @@ ssize_t nfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -173,8 +173,8 @@ ssize_t nfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
VM_BUG_ON(iov_iter_count(iter) != PAGE_SIZE); VM_BUG_ON(iov_iter_count(iter) != PAGE_SIZE);
if (iov_iter_rw(iter) == READ) if (iov_iter_rw(iter) == READ)
return nfs_file_direct_read(iocb, iter); return nfs_file_direct_read(iocb, iter, true);
return nfs_file_direct_write(iocb, iter); return nfs_file_direct_write(iocb, iter, true);
} }
static void nfs_direct_release_pages(struct page **pages, unsigned int npages) static void nfs_direct_release_pages(struct page **pages, unsigned int npages)
...@@ -425,6 +425,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -425,6 +425,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
* nfs_file_direct_read - file direct read operation for NFS files * nfs_file_direct_read - file direct read operation for NFS files
* @iocb: target I/O control block * @iocb: target I/O control block
* @iter: vector of user buffers into which to read data * @iter: vector of user buffers into which to read data
* @swap: flag indicating this is swap IO, not O_DIRECT IO
* *
* We use this function for direct reads instead of calling * We use this function for direct reads instead of calling
* generic_file_aio_read() in order to avoid gfar's check to see if * generic_file_aio_read() in order to avoid gfar's check to see if
...@@ -440,7 +441,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -440,7 +441,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
* client must read the updated atime from the server back into its * client must read the updated atime from the server back into its
* cache. * cache.
*/ */
ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
bool swap)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
...@@ -482,11 +484,13 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ...@@ -482,11 +484,13 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if (iter_is_iovec(iter)) if (iter_is_iovec(iter))
dreq->flags = NFS_ODIRECT_SHOULD_DIRTY; dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;
if (!swap)
nfs_start_io_direct(inode); nfs_start_io_direct(inode);
NFS_I(inode)->read_io += count; NFS_I(inode)->read_io += count;
requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
if (!swap)
nfs_end_io_direct(inode); nfs_end_io_direct(inode);
if (requested > 0) { if (requested > 0) {
...@@ -790,7 +794,7 @@ static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { ...@@ -790,7 +794,7 @@ static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
*/ */
static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
struct iov_iter *iter, struct iov_iter *iter,
loff_t pos) loff_t pos, int ioflags)
{ {
struct nfs_pageio_descriptor desc; struct nfs_pageio_descriptor desc;
struct inode *inode = dreq->inode; struct inode *inode = dreq->inode;
...@@ -798,7 +802,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -798,7 +802,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
size_t requested_bytes = 0; size_t requested_bytes = 0;
size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE); size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE);
nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE, false, nfs_pageio_init_write(&desc, inode, ioflags, false,
&nfs_direct_write_completion_ops); &nfs_direct_write_completion_ops);
desc.pg_dreq = dreq; desc.pg_dreq = dreq;
get_dreq(dreq); get_dreq(dreq);
...@@ -876,6 +880,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -876,6 +880,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
* nfs_file_direct_write - file direct write operation for NFS files * nfs_file_direct_write - file direct write operation for NFS files
* @iocb: target I/O control block * @iocb: target I/O control block
* @iter: vector of user buffers from which to write data * @iter: vector of user buffers from which to write data
* @swap: flag indicating this is swap IO, not O_DIRECT IO
* *
* We use this function for direct writes instead of calling * We use this function for direct writes instead of calling
* generic_file_aio_write() in order to avoid taking the inode * generic_file_aio_write() in order to avoid taking the inode
...@@ -892,7 +897,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -892,7 +897,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
* Note that O_APPEND is not supported for NFS direct writes, as there * Note that O_APPEND is not supported for NFS direct writes, as there
* is no atomic O_APPEND write facility in the NFS protocol. * is no atomic O_APPEND write facility in the NFS protocol.
*/ */
ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter,
bool swap)
{ {
ssize_t result, requested; ssize_t result, requested;
size_t count; size_t count;
...@@ -906,6 +912,10 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -906,6 +912,10 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n", dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n",
file, iov_iter_count(iter), (long long) iocb->ki_pos); file, iov_iter_count(iter), (long long) iocb->ki_pos);
if (swap)
/* bypass generic checks */
result = iov_iter_count(iter);
else
result = generic_write_checks(iocb, iter); result = generic_write_checks(iocb, iter);
if (result <= 0) if (result <= 0)
return result; return result;
...@@ -937,9 +947,14 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -937,9 +947,14 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
dreq->iocb = iocb; dreq->iocb = iocb;
pnfs_init_ds_commit_info_ops(&dreq->ds_cinfo, inode); pnfs_init_ds_commit_info_ops(&dreq->ds_cinfo, inode);
if (swap) {
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
FLUSH_STABLE);
} else {
nfs_start_io_direct(inode); nfs_start_io_direct(inode);
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos); requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
FLUSH_COND_STABLE);
if (mapping->nrpages) { if (mapping->nrpages) {
invalidate_inode_pages2_range(mapping, invalidate_inode_pages2_range(mapping,
...@@ -947,6 +962,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -947,6 +962,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
} }
nfs_end_io_direct(inode); nfs_end_io_direct(inode);
}
if (requested > 0) { if (requested > 0) {
result = nfs_direct_wait(dreq); result = nfs_direct_wait(dreq);
......
...@@ -44,11 +44,6 @@ ...@@ -44,11 +44,6 @@
static const struct vm_operations_struct nfs_file_vm_ops; static const struct vm_operations_struct nfs_file_vm_ops;
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
#endif
int nfs_check_flags(int flags) int nfs_check_flags(int flags)
{ {
if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT)) if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
...@@ -162,7 +157,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) ...@@ -162,7 +157,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
ssize_t result; ssize_t result;
if (iocb->ki_flags & IOCB_DIRECT) if (iocb->ki_flags & IOCB_DIRECT)
return nfs_file_direct_read(iocb, to); return nfs_file_direct_read(iocb, to, false);
dprintk("NFS: read(%pD2, %zu@%lu)\n", dprintk("NFS: read(%pD2, %zu@%lu)\n",
iocb->ki_filp, iocb->ki_filp,
...@@ -488,8 +483,9 @@ static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file, ...@@ -488,8 +483,9 @@ static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
{ {
unsigned long blocks; unsigned long blocks;
long long isize; long long isize;
struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host); struct inode *inode = file_inode(file);
struct inode *inode = file->f_mapping->host; struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_client *cl = NFS_SERVER(inode)->nfs_client;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
blocks = inode->i_blocks; blocks = inode->i_blocks;
...@@ -502,19 +498,27 @@ static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file, ...@@ -502,19 +498,27 @@ static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
*span = sis->pages; *span = sis->pages;
if (cl->rpc_ops->enable_swap)
cl->rpc_ops->enable_swap(inode);
return rpc_clnt_swap_activate(clnt); return rpc_clnt_swap_activate(clnt);
} }
static void nfs_swap_deactivate(struct file *file) static void nfs_swap_deactivate(struct file *file)
{ {
struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host); struct inode *inode = file_inode(file);
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_client *cl = NFS_SERVER(inode)->nfs_client;
rpc_clnt_swap_deactivate(clnt); rpc_clnt_swap_deactivate(clnt);
if (cl->rpc_ops->disable_swap)
cl->rpc_ops->disable_swap(file_inode(file));
} }
const struct address_space_operations nfs_file_aops = { const struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage, .readpage = nfs_readpage,
.readpages = nfs_readpages, .readahead = nfs_readahead,
.dirty_folio = filemap_dirty_folio, .dirty_folio = filemap_dirty_folio,
.writepage = nfs_writepage, .writepage = nfs_writepage,
.writepages = nfs_writepages, .writepages = nfs_writepages,
...@@ -619,7 +623,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -619,7 +623,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
return result; return result;
if (iocb->ki_flags & IOCB_DIRECT) if (iocb->ki_flags & IOCB_DIRECT)
return nfs_file_direct_write(iocb, from); return nfs_file_direct_write(iocb, from, false);
dprintk("NFS: write(%pD2, %zu@%Ld)\n", dprintk("NFS: write(%pD2, %zu@%Ld)\n",
file, iov_iter_count(from), (long long) iocb->ki_pos); file, iov_iter_count(from), (long long) iocb->ki_pos);
......
...@@ -1075,7 +1075,7 @@ filelayout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo, ...@@ -1075,7 +1075,7 @@ filelayout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
unsigned int size = (fl->stripe_type == STRIPE_SPARSE) ? unsigned int size = (fl->stripe_type == STRIPE_SPARSE) ?
fl->dsaddr->ds_num : fl->dsaddr->stripe_count; fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
new = pnfs_alloc_commit_array(size, GFP_NOIO); new = pnfs_alloc_commit_array(size, nfs_io_gfp_mask());
if (new) { if (new) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
array = pnfs_add_commit_array(fl_cinfo, new, lseg); array = pnfs_add_commit_array(fl_cinfo, new, lseg);
......
...@@ -663,7 +663,7 @@ nfs4_ff_layout_stat_io_start_read(struct inode *inode, ...@@ -663,7 +663,7 @@ nfs4_ff_layout_stat_io_start_read(struct inode *inode,
spin_unlock(&mirror->lock); spin_unlock(&mirror->lock);
if (report) if (report)
pnfs_report_layoutstat(inode, GFP_KERNEL); pnfs_report_layoutstat(inode, nfs_io_gfp_mask());
} }
static void static void
...@@ -694,7 +694,7 @@ nfs4_ff_layout_stat_io_start_write(struct inode *inode, ...@@ -694,7 +694,7 @@ nfs4_ff_layout_stat_io_start_write(struct inode *inode,
spin_unlock(&mirror->lock); spin_unlock(&mirror->lock);
if (report) if (report)
pnfs_report_layoutstat(inode, GFP_NOIO); pnfs_report_layoutstat(inode, nfs_io_gfp_mask());
} }
static void static void
...@@ -806,13 +806,10 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio, ...@@ -806,13 +806,10 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,
bool strict_iomode) bool strict_iomode)
{ {
pnfs_put_lseg(pgio->pg_lseg); pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg =
nfs_req_openctx(req), pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req_offset(req), req->wb_bytes, IOMODE_READ,
req->wb_bytes, strict_iomode, nfs_io_gfp_mask());
IOMODE_READ,
strict_iomode,
GFP_KERNEL);
if (IS_ERR(pgio->pg_lseg)) { if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg); pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
...@@ -894,13 +891,10 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -894,13 +891,10 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
retry: retry:
ff_layout_pg_check_layout(pgio, req); ff_layout_pg_check_layout(pgio, req);
if (!pgio->pg_lseg) { if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg =
nfs_req_openctx(req), pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req_offset(req), req->wb_bytes,
req->wb_bytes, IOMODE_RW, false, nfs_io_gfp_mask());
IOMODE_RW,
false,
GFP_NOFS);
if (IS_ERR(pgio->pg_lseg)) { if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg); pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
...@@ -953,13 +947,10 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio, ...@@ -953,13 +947,10 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req) struct nfs_page *req)
{ {
if (!pgio->pg_lseg) { if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg =
nfs_req_openctx(req), pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req_offset(req), req->wb_bytes,
req->wb_bytes, IOMODE_RW, false, nfs_io_gfp_mask());
IOMODE_RW,
false,
GFP_NOFS);
if (IS_ERR(pgio->pg_lseg)) { if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg); pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
...@@ -1258,7 +1249,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, ...@@ -1258,7 +1249,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
mirror = FF_LAYOUT_COMP(lseg, idx); mirror = FF_LAYOUT_COMP(lseg, idx);
err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, offset, length, status, opnum, mirror, offset, length, status, opnum,
GFP_NOIO); nfs_io_gfp_mask());
switch (status) { switch (status) {
case NFS4ERR_DELAY: case NFS4ERR_DELAY:
...@@ -1973,7 +1964,8 @@ ff_layout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo, ...@@ -1973,7 +1964,8 @@ ff_layout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
struct inode *inode = lseg->pls_layout->plh_inode; struct inode *inode = lseg->pls_layout->plh_inode;
struct pnfs_commit_array *array, *new; struct pnfs_commit_array *array, *new;
new = pnfs_alloc_commit_array(flseg->mirror_array_cnt, GFP_NOIO); new = pnfs_alloc_commit_array(flseg->mirror_array_cnt,
nfs_io_gfp_mask());
if (new) { if (new) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
array = pnfs_add_commit_array(fl_cinfo, new, lseg); array = pnfs_add_commit_array(fl_cinfo, new, lseg);
...@@ -2152,10 +2144,10 @@ ff_layout_prepare_layoutreturn(struct nfs4_layoutreturn_args *args) ...@@ -2152,10 +2144,10 @@ ff_layout_prepare_layoutreturn(struct nfs4_layoutreturn_args *args)
struct nfs4_flexfile_layoutreturn_args *ff_args; struct nfs4_flexfile_layoutreturn_args *ff_args;
struct nfs4_flexfile_layout *ff_layout = FF_LAYOUT_FROM_HDR(args->layout); struct nfs4_flexfile_layout *ff_layout = FF_LAYOUT_FROM_HDR(args->layout);
ff_args = kmalloc(sizeof(*ff_args), GFP_KERNEL); ff_args = kmalloc(sizeof(*ff_args), nfs_io_gfp_mask());
if (!ff_args) if (!ff_args)
goto out_nomem; goto out_nomem;
ff_args->pages[0] = alloc_page(GFP_KERNEL); ff_args->pages[0] = alloc_page(nfs_io_gfp_mask());
if (!ff_args->pages[0]) if (!ff_args->pages[0])
goto out_nomem_free; goto out_nomem_free;
...@@ -2192,8 +2184,8 @@ ff_layout_send_layouterror(struct pnfs_layout_segment *lseg) ...@@ -2192,8 +2184,8 @@ ff_layout_send_layouterror(struct pnfs_layout_segment *lseg)
if (list_empty(&head)) if (list_empty(&head))
return; return;
errors = kmalloc_array(NFS42_LAYOUTERROR_MAX, errors = kmalloc_array(NFS42_LAYOUTERROR_MAX, sizeof(*errors),
sizeof(*errors), GFP_NOFS); nfs_io_gfp_mask());
if (errors != NULL) { if (errors != NULL) {
const struct nfs4_ff_layout_ds_err *pos; const struct nfs4_ff_layout_ds_err *pos;
size_t n = 0; size_t n = 0;
...@@ -2444,7 +2436,8 @@ ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args) ...@@ -2444,7 +2436,8 @@ ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args)
const int dev_count = PNFS_LAYOUTSTATS_MAXDEV; const int dev_count = PNFS_LAYOUTSTATS_MAXDEV;
/* For now, send at most PNFS_LAYOUTSTATS_MAXDEV statistics */ /* For now, send at most PNFS_LAYOUTSTATS_MAXDEV statistics */
args->devinfo = kmalloc_array(dev_count, sizeof(*args->devinfo), GFP_NOIO); args->devinfo = kmalloc_array(dev_count, sizeof(*args->devinfo),
nfs_io_gfp_mask());
if (!args->devinfo) if (!args->devinfo)
return -ENOMEM; return -ENOMEM;
......
...@@ -80,6 +80,7 @@ enum nfs_param { ...@@ -80,6 +80,7 @@ enum nfs_param {
Opt_source, Opt_source,
Opt_tcp, Opt_tcp,
Opt_timeo, Opt_timeo,
Opt_trunkdiscovery,
Opt_udp, Opt_udp,
Opt_v, Opt_v,
Opt_vers, Opt_vers,
...@@ -180,6 +181,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = { ...@@ -180,6 +181,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
fsparam_string("source", Opt_source), fsparam_string("source", Opt_source),
fsparam_flag ("tcp", Opt_tcp), fsparam_flag ("tcp", Opt_tcp),
fsparam_u32 ("timeo", Opt_timeo), fsparam_u32 ("timeo", Opt_timeo),
fsparam_flag_no("trunkdiscovery", Opt_trunkdiscovery),
fsparam_flag ("udp", Opt_udp), fsparam_flag ("udp", Opt_udp),
fsparam_flag ("v2", Opt_v), fsparam_flag ("v2", Opt_v),
fsparam_flag ("v3", Opt_v), fsparam_flag ("v3", Opt_v),
...@@ -529,6 +531,12 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, ...@@ -529,6 +531,12 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
else else
ctx->flags &= ~NFS_MOUNT_NOCTO; ctx->flags &= ~NFS_MOUNT_NOCTO;
break; break;
case Opt_trunkdiscovery:
if (result.negated)
ctx->flags &= ~NFS_MOUNT_TRUNK_DISCOVERY;
else
ctx->flags |= NFS_MOUNT_TRUNK_DISCOVERY;
break;
case Opt_ac: case Opt_ac:
if (result.negated) if (result.negated)
ctx->flags |= NFS_MOUNT_NOAC; ctx->flags |= NFS_MOUNT_NOAC;
......
...@@ -19,8 +19,7 @@ ...@@ -19,8 +19,7 @@
#include "internal.h" #include "internal.h"
#include "iostat.h" #include "iostat.h"
#include "fscache.h" #include "fscache.h"
#include "nfstrace.h"
#define NFSDBG_FACILITY NFSDBG_FSCACHE
#define NFS_MAX_KEY_LEN 1000 #define NFS_MAX_KEY_LEN 1000
...@@ -128,8 +127,6 @@ int nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int u ...@@ -128,8 +127,6 @@ int nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int u
vcookie = fscache_acquire_volume(key, vcookie = fscache_acquire_volume(key,
NULL, /* preferred_cache */ NULL, /* preferred_cache */
NULL, 0 /* coherency_data */); NULL, 0 /* coherency_data */);
dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
nfss, vcookie);
if (IS_ERR(vcookie)) { if (IS_ERR(vcookie)) {
if (vcookie != ERR_PTR(-EBUSY)) { if (vcookie != ERR_PTR(-EBUSY)) {
kfree(key); kfree(key);
...@@ -152,9 +149,6 @@ void nfs_fscache_release_super_cookie(struct super_block *sb) ...@@ -152,9 +149,6 @@ void nfs_fscache_release_super_cookie(struct super_block *sb)
{ {
struct nfs_server *nfss = NFS_SB(sb); struct nfs_server *nfss = NFS_SB(sb);
dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n",
nfss, nfss->fscache);
fscache_relinquish_volume(nfss->fscache, NULL, false); fscache_relinquish_volume(nfss->fscache, NULL, false);
nfss->fscache = NULL; nfss->fscache = NULL;
kfree(nfss->fscache_uniq); kfree(nfss->fscache_uniq);
...@@ -173,7 +167,7 @@ void nfs_fscache_init_inode(struct inode *inode) ...@@ -173,7 +167,7 @@ void nfs_fscache_init_inode(struct inode *inode)
if (!(nfss->fscache && S_ISREG(inode->i_mode))) if (!(nfss->fscache && S_ISREG(inode->i_mode)))
return; return;
nfs_fscache_update_auxdata(&auxdata, nfsi); nfs_fscache_update_auxdata(&auxdata, inode);
nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache, nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache,
0, 0,
...@@ -181,7 +175,7 @@ void nfs_fscache_init_inode(struct inode *inode) ...@@ -181,7 +175,7 @@ void nfs_fscache_init_inode(struct inode *inode)
nfsi->fh.size, nfsi->fh.size,
&auxdata, /* aux_data */ &auxdata, /* aux_data */
sizeof(auxdata), sizeof(auxdata),
i_size_read(&nfsi->vfs_inode)); i_size_read(inode));
} }
/* /*
...@@ -192,8 +186,6 @@ void nfs_fscache_clear_inode(struct inode *inode) ...@@ -192,8 +186,6 @@ void nfs_fscache_clear_inode(struct inode *inode)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct fscache_cookie *cookie = nfs_i_fscache(inode); struct fscache_cookie *cookie = nfs_i_fscache(inode);
dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie);
fscache_relinquish_cookie(cookie, false); fscache_relinquish_cookie(cookie, false);
nfsi->fscache = NULL; nfsi->fscache = NULL;
} }
...@@ -220,7 +212,6 @@ void nfs_fscache_clear_inode(struct inode *inode) ...@@ -220,7 +212,6 @@ void nfs_fscache_clear_inode(struct inode *inode)
void nfs_fscache_open_file(struct inode *inode, struct file *filp) void nfs_fscache_open_file(struct inode *inode, struct file *filp)
{ {
struct nfs_fscache_inode_auxdata auxdata; struct nfs_fscache_inode_auxdata auxdata;
struct nfs_inode *nfsi = NFS_I(inode);
struct fscache_cookie *cookie = nfs_i_fscache(inode); struct fscache_cookie *cookie = nfs_i_fscache(inode);
bool open_for_write = inode_is_open_for_write(inode); bool open_for_write = inode_is_open_for_write(inode);
...@@ -229,8 +220,7 @@ void nfs_fscache_open_file(struct inode *inode, struct file *filp) ...@@ -229,8 +220,7 @@ void nfs_fscache_open_file(struct inode *inode, struct file *filp)
fscache_use_cookie(cookie, open_for_write); fscache_use_cookie(cookie, open_for_write);
if (open_for_write) { if (open_for_write) {
dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi); nfs_fscache_update_auxdata(&auxdata, inode);
nfs_fscache_update_auxdata(&auxdata, nfsi);
fscache_invalidate(cookie, &auxdata, i_size_read(inode), fscache_invalidate(cookie, &auxdata, i_size_read(inode),
FSCACHE_INVAL_DIO_WRITE); FSCACHE_INVAL_DIO_WRITE);
} }
...@@ -240,11 +230,10 @@ EXPORT_SYMBOL_GPL(nfs_fscache_open_file); ...@@ -240,11 +230,10 @@ EXPORT_SYMBOL_GPL(nfs_fscache_open_file);
void nfs_fscache_release_file(struct inode *inode, struct file *filp) void nfs_fscache_release_file(struct inode *inode, struct file *filp)
{ {
struct nfs_fscache_inode_auxdata auxdata; struct nfs_fscache_inode_auxdata auxdata;
struct nfs_inode *nfsi = NFS_I(inode);
struct fscache_cookie *cookie = nfs_i_fscache(inode); struct fscache_cookie *cookie = nfs_i_fscache(inode);
if (fscache_cookie_valid(cookie)) { if (fscache_cookie_valid(cookie)) {
nfs_fscache_update_auxdata(&auxdata, nfsi); nfs_fscache_update_auxdata(&auxdata, inode);
fscache_unuse_cookie(cookie, &auxdata, NULL); fscache_unuse_cookie(cookie, &auxdata, NULL);
} }
} }
...@@ -319,58 +308,50 @@ static int fscache_fallback_write_page(struct inode *inode, struct page *page, ...@@ -319,58 +308,50 @@ static int fscache_fallback_write_page(struct inode *inode, struct page *page,
/* /*
* Retrieve a page from fscache * Retrieve a page from fscache
*/ */
int __nfs_readpage_from_fscache(struct inode *inode, struct page *page) int __nfs_fscache_read_page(struct inode *inode, struct page *page)
{ {
int ret; int ret;
dfprintk(FSCACHE, trace_nfs_fscache_read_page(inode, page);
"NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n",
nfs_i_fscache(inode), page, page->index, page->flags, inode);
if (PageChecked(page)) { if (PageChecked(page)) {
dfprintk(FSCACHE, "NFS: readpage_from_fscache: PageChecked\n");
ClearPageChecked(page); ClearPageChecked(page);
return 1; ret = 1;
goto out;
} }
ret = fscache_fallback_read_page(inode, page); ret = fscache_fallback_read_page(inode, page);
if (ret < 0) { if (ret < 0) {
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL); nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL);
dfprintk(FSCACHE,
"NFS: readpage_from_fscache failed %d\n", ret);
SetPageChecked(page); SetPageChecked(page);
return ret; goto out;
} }
/* Read completed synchronously */ /* Read completed synchronously */
dfprintk(FSCACHE, "NFS: readpage_from_fscache: read successful\n");
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK); nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK);
SetPageUptodate(page); SetPageUptodate(page);
return 0; ret = 0;
out:
trace_nfs_fscache_read_page_exit(inode, page, ret);
return ret;
} }
/* /*
* Store a newly fetched page in fscache. We can be certain there's no page * Store a newly fetched page in fscache. We can be certain there's no page
* stored in the cache as yet otherwise we would've read it from there. * stored in the cache as yet otherwise we would've read it from there.
*/ */
void __nfs_readpage_to_fscache(struct inode *inode, struct page *page) void __nfs_fscache_write_page(struct inode *inode, struct page *page)
{ {
int ret; int ret;
dfprintk(FSCACHE, trace_nfs_fscache_write_page(inode, page);
"NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx))\n",
nfs_i_fscache(inode), page, page->index, page->flags);
ret = fscache_fallback_write_page(inode, page, true); ret = fscache_fallback_write_page(inode, page, true);
dfprintk(FSCACHE,
"NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n",
page, page->index, page->flags, ret);
if (ret != 0) { if (ret != 0) {
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL); nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL);
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED); nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED);
} else { } else {
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_OK); nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_OK);
} }
trace_nfs_fscache_write_page_exit(inode, page, ret);
} }
...@@ -45,10 +45,8 @@ extern void nfs_fscache_clear_inode(struct inode *); ...@@ -45,10 +45,8 @@ extern void nfs_fscache_clear_inode(struct inode *);
extern void nfs_fscache_open_file(struct inode *, struct file *); extern void nfs_fscache_open_file(struct inode *, struct file *);
extern void nfs_fscache_release_file(struct inode *, struct file *); extern void nfs_fscache_release_file(struct inode *, struct file *);
extern int __nfs_readpage_from_fscache(struct inode *, struct page *); extern int __nfs_fscache_read_page(struct inode *, struct page *);
extern void __nfs_read_completion_to_fscache(struct nfs_pgio_header *hdr, extern void __nfs_fscache_write_page(struct inode *, struct page *);
unsigned long bytes);
extern void __nfs_readpage_to_fscache(struct inode *, struct page *);
static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp) static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
{ {
...@@ -66,11 +64,10 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp) ...@@ -66,11 +64,10 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
/* /*
* Retrieve a page from an inode data storage object. * Retrieve a page from an inode data storage object.
*/ */
static inline int nfs_readpage_from_fscache(struct inode *inode, static inline int nfs_fscache_read_page(struct inode *inode, struct page *page)
struct page *page)
{ {
if (NFS_I(inode)->fscache) if (nfs_i_fscache(inode))
return __nfs_readpage_from_fscache(inode, page); return __nfs_fscache_read_page(inode, page);
return -ENOBUFS; return -ENOBUFS;
} }
...@@ -78,24 +75,24 @@ static inline int nfs_readpage_from_fscache(struct inode *inode, ...@@ -78,24 +75,24 @@ static inline int nfs_readpage_from_fscache(struct inode *inode,
* Store a page newly fetched from the server in an inode data storage object * Store a page newly fetched from the server in an inode data storage object
* in the cache. * in the cache.
*/ */
static inline void nfs_readpage_to_fscache(struct inode *inode, static inline void nfs_fscache_write_page(struct inode *inode,
struct page *page) struct page *page)
{ {
if (NFS_I(inode)->fscache) if (nfs_i_fscache(inode))
__nfs_readpage_to_fscache(inode, page); __nfs_fscache_write_page(inode, page);
} }
static inline void nfs_fscache_update_auxdata(struct nfs_fscache_inode_auxdata *auxdata, static inline void nfs_fscache_update_auxdata(struct nfs_fscache_inode_auxdata *auxdata,
struct nfs_inode *nfsi) struct inode *inode)
{ {
memset(auxdata, 0, sizeof(*auxdata)); memset(auxdata, 0, sizeof(*auxdata));
auxdata->mtime_sec = nfsi->vfs_inode.i_mtime.tv_sec; auxdata->mtime_sec = inode->i_mtime.tv_sec;
auxdata->mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec; auxdata->mtime_nsec = inode->i_mtime.tv_nsec;
auxdata->ctime_sec = nfsi->vfs_inode.i_ctime.tv_sec; auxdata->ctime_sec = inode->i_ctime.tv_sec;
auxdata->ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec; auxdata->ctime_nsec = inode->i_ctime.tv_nsec;
if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4) if (NFS_SERVER(inode)->nfs_client->rpc_ops->version == 4)
auxdata->change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode); auxdata->change_attr = inode_peek_iversion_raw(inode);
} }
/* /*
...@@ -107,9 +104,9 @@ static inline void nfs_fscache_invalidate(struct inode *inode, int flags) ...@@ -107,9 +104,9 @@ static inline void nfs_fscache_invalidate(struct inode *inode, int flags)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
if (nfsi->fscache) { if (nfsi->fscache) {
nfs_fscache_update_auxdata(&auxdata, nfsi); nfs_fscache_update_auxdata(&auxdata, inode);
fscache_invalidate(nfsi->fscache, &auxdata, fscache_invalidate(nfsi->fscache, &auxdata,
i_size_read(&nfsi->vfs_inode), flags); i_size_read(inode), flags);
} }
} }
...@@ -136,15 +133,11 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp) ...@@ -136,15 +133,11 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
{ {
return 1; /* True: may release page */ return 1; /* True: may release page */
} }
static inline int nfs_readpage_from_fscache(struct inode *inode, static inline int nfs_fscache_read_page(struct inode *inode, struct page *page)
struct page *page)
{ {
return -ENOBUFS; return -ENOBUFS;
} }
static inline void nfs_readpage_to_fscache(struct inode *inode, static inline void nfs_fscache_write_page(struct inode *inode, struct page *page) {}
struct page *page) {}
static inline void nfs_fscache_invalidate(struct inode *inode, int flags) {} static inline void nfs_fscache_invalidate(struct inode *inode, int flags) {}
static inline const char *nfs_server_fscache_state(struct nfs_server *server) static inline const char *nfs_server_fscache_state(struct nfs_server *server)
......
...@@ -203,14 +203,13 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags) ...@@ -203,14 +203,13 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
NFS_INO_INVALID_OTHER | NFS_INO_INVALID_OTHER |
NFS_INO_INVALID_XATTR); NFS_INO_INVALID_XATTR);
flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE); flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
} else if (flags & NFS_INO_REVAL_PAGECACHE) }
flags |= NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE;
if (!nfs_has_xattr_cache(nfsi)) if (!nfs_has_xattr_cache(nfsi))
flags &= ~NFS_INO_INVALID_XATTR; flags &= ~NFS_INO_INVALID_XATTR;
if (flags & NFS_INO_INVALID_DATA) if (flags & NFS_INO_INVALID_DATA)
nfs_fscache_invalidate(inode, 0); nfs_fscache_invalidate(inode, 0);
flags &= ~(NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED); flags &= ~NFS_INO_REVAL_FORCED;
nfsi->cache_validity |= flags; nfsi->cache_validity |= flags;
...@@ -236,19 +235,17 @@ static void nfs_zap_caches_locked(struct inode *inode) ...@@ -236,19 +235,17 @@ static void nfs_zap_caches_locked(struct inode *inode)
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = jiffies; nfsi->attrtimeo_timestamp = jiffies;
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR |
| NFS_INO_INVALID_DATA NFS_INO_INVALID_DATA |
| NFS_INO_INVALID_ACCESS NFS_INO_INVALID_ACCESS |
| NFS_INO_INVALID_ACL NFS_INO_INVALID_ACL |
| NFS_INO_INVALID_XATTR NFS_INO_INVALID_XATTR);
| NFS_INO_REVAL_PAGECACHE); else
} else nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR |
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR NFS_INO_INVALID_ACCESS |
| NFS_INO_INVALID_ACCESS NFS_INO_INVALID_ACL |
| NFS_INO_INVALID_ACL NFS_INO_INVALID_XATTR);
| NFS_INO_INVALID_XATTR
| NFS_INO_REVAL_PAGECACHE);
nfs_zap_label_cache_locked(nfsi); nfs_zap_label_cache_locked(nfsi);
} }
...@@ -564,8 +561,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -564,8 +561,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
inode->i_gid = fattr->gid; inode->i_gid = fattr->gid;
else if (fattr_supported & NFS_ATTR_FATTR_GROUP) else if (fattr_supported & NFS_ATTR_FATTR_GROUP)
nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
if (nfs_server_capable(inode, NFS_CAP_XATTR))
nfs_set_cache_invalid(inode, NFS_INO_INVALID_XATTR);
if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blocks = fattr->du.nfs2.blocks;
else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED && else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED &&
...@@ -785,26 +780,32 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, ...@@ -785,26 +780,32 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
} }
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
static void nfs_readdirplus_parent_cache_miss(struct dentry *dentry) /*
* Don't request help from readdirplus if the file is being written to,
* or if attribute caching is turned off
*/
static bool nfs_getattr_readdirplus_enable(const struct inode *inode)
{ {
struct dentry *parent; return nfs_server_capable(inode, NFS_CAP_READDIRPLUS) &&
!nfs_have_writebacks(inode) && NFS_MAXATTRTIMEO(inode) > 5 * HZ;
}
if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS)) static void nfs_readdirplus_parent_cache_miss(struct dentry *dentry)
return; {
parent = dget_parent(dentry); if (!IS_ROOT(dentry)) {
nfs_force_use_readdirplus(d_inode(parent)); struct dentry *parent = dget_parent(dentry);
nfs_readdir_record_entry_cache_miss(d_inode(parent));
dput(parent); dput(parent);
}
} }
static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry) static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
{ {
struct dentry *parent; if (!IS_ROOT(dentry)) {
struct dentry *parent = dget_parent(dentry);
if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS)) nfs_readdir_record_entry_cache_hit(d_inode(parent));
return;
parent = dget_parent(dentry);
nfs_advise_use_readdirplus(d_inode(parent));
dput(parent); dput(parent);
}
} }
static u32 nfs_get_valid_attrmask(struct inode *inode) static u32 nfs_get_valid_attrmask(struct inode *inode)
...@@ -840,6 +841,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path, ...@@ -840,6 +841,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
int err = 0; int err = 0;
bool force_sync = query_flags & AT_STATX_FORCE_SYNC; bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
bool do_update = false; bool do_update = false;
bool readdirplus_enabled = nfs_getattr_readdirplus_enable(inode);
trace_nfs_getattr_enter(inode); trace_nfs_getattr_enter(inode);
...@@ -848,6 +850,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path, ...@@ -848,6 +850,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
STATX_INO | STATX_SIZE | STATX_BLOCKS; STATX_INO | STATX_SIZE | STATX_BLOCKS;
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) { if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
if (readdirplus_enabled)
nfs_readdirplus_parent_cache_hit(path->dentry); nfs_readdirplus_parent_cache_hit(path->dentry);
goto out_no_revalidate; goto out_no_revalidate;
} }
...@@ -898,15 +901,12 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path, ...@@ -898,15 +901,12 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS; do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
if (do_update) { if (do_update) {
/* Update the attribute cache */ if (readdirplus_enabled)
if (!(server->flags & NFS_MOUNT_NOAC))
nfs_readdirplus_parent_cache_miss(path->dentry); nfs_readdirplus_parent_cache_miss(path->dentry);
else
nfs_readdirplus_parent_cache_hit(path->dentry);
err = __nfs_revalidate_inode(server, inode); err = __nfs_revalidate_inode(server, inode);
if (err) if (err)
goto out; goto out;
} else } else if (readdirplus_enabled)
nfs_readdirplus_parent_cache_hit(path->dentry); nfs_readdirplus_parent_cache_hit(path->dentry);
out_no_revalidate: out_no_revalidate:
/* Only return attributes that were revalidated. */ /* Only return attributes that were revalidated. */
...@@ -952,7 +952,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) ...@@ -952,7 +952,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
res = __nfs_find_lock_context(ctx); res = __nfs_find_lock_context(ctx);
rcu_read_unlock(); rcu_read_unlock();
if (res == NULL) { if (res == NULL) {
new = kmalloc(sizeof(*new), GFP_KERNEL); new = kmalloc(sizeof(*new), GFP_KERNEL_ACCOUNT);
if (new == NULL) if (new == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
nfs_init_lock_context(new); nfs_init_lock_context(new);
...@@ -1030,7 +1030,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, ...@@ -1030,7 +1030,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
{ {
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
if (!ctx) if (!ctx)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
nfs_sb_active(dentry->d_sb); nfs_sb_active(dentry->d_sb);
...@@ -1583,7 +1583,7 @@ struct nfs_fattr *nfs_alloc_fattr(void) ...@@ -1583,7 +1583,7 @@ struct nfs_fattr *nfs_alloc_fattr(void)
{ {
struct nfs_fattr *fattr; struct nfs_fattr *fattr;
fattr = kmalloc(sizeof(*fattr), GFP_NOFS); fattr = kmalloc(sizeof(*fattr), GFP_KERNEL);
if (fattr != NULL) { if (fattr != NULL) {
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
fattr->label = NULL; fattr->label = NULL;
...@@ -1599,7 +1599,7 @@ struct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server) ...@@ -1599,7 +1599,7 @@ struct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server)
if (!fattr) if (!fattr)
return NULL; return NULL;
fattr->label = nfs4_label_alloc(server, GFP_NOFS); fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
if (IS_ERR(fattr->label)) { if (IS_ERR(fattr->label)) {
kfree(fattr); kfree(fattr);
return NULL; return NULL;
...@@ -1613,7 +1613,7 @@ struct nfs_fh *nfs_alloc_fhandle(void) ...@@ -1613,7 +1613,7 @@ struct nfs_fh *nfs_alloc_fhandle(void)
{ {
struct nfs_fh *fh; struct nfs_fh *fh;
fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS); fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
if (fh != NULL) if (fh != NULL)
fh->size = 0; fh->size = 0;
return fh; return fh;
......
...@@ -366,8 +366,8 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp, ...@@ -366,8 +366,8 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
const struct nfs_client_initdata *); const struct nfs_client_initdata *);
/* dir.c */ /* dir.c */
extern void nfs_advise_use_readdirplus(struct inode *dir); extern void nfs_readdir_record_entry_cache_hit(struct inode *dir);
extern void nfs_force_use_readdirplus(struct inode *dir); extern void nfs_readdir_record_entry_cache_miss(struct inode *dir);
extern unsigned long nfs_access_cache_count(struct shrinker *shrink, extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
struct shrink_control *sc); struct shrink_control *sc);
extern unsigned long nfs_access_cache_scan(struct shrinker *shrink, extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
...@@ -388,6 +388,20 @@ int nfs_mknod(struct user_namespace *, struct inode *, struct dentry *, umode_t, ...@@ -388,6 +388,20 @@ int nfs_mknod(struct user_namespace *, struct inode *, struct dentry *, umode_t,
int nfs_rename(struct user_namespace *, struct inode *, struct dentry *, int nfs_rename(struct user_namespace *, struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int); struct inode *, struct dentry *, unsigned int);
#ifdef CONFIG_NFS_V4_2
static inline __u32 nfs_access_xattr_mask(const struct nfs_server *server)
{
if (!(server->caps & NFS_CAP_XATTR))
return 0;
return NFS4_ACCESS_XAREAD | NFS4_ACCESS_XAWRITE | NFS4_ACCESS_XALIST;
}
#else
static inline __u32 nfs_access_xattr_mask(const struct nfs_server *server)
{
return 0;
}
#endif
/* file.c */ /* file.c */
int nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); int nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
loff_t nfs_file_llseek(struct file *, loff_t, int); loff_t nfs_file_llseek(struct file *, loff_t, int);
...@@ -573,6 +587,13 @@ nfs_write_match_verf(const struct nfs_writeverf *verf, ...@@ -573,6 +587,13 @@ nfs_write_match_verf(const struct nfs_writeverf *verf,
!nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier); !nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier);
} }
static inline gfp_t nfs_io_gfp_mask(void)
{
if (current->flags & PF_WQ_WORKER)
return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
return GFP_KERNEL;
}
/* unlink.c */ /* unlink.c */
extern struct rpc_task * extern struct rpc_task *
nfs_async_rename(struct inode *old_dir, struct inode *new_dir, nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
......
...@@ -949,13 +949,12 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -949,13 +949,12 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
error = decode_filename_inline(xdr, &entry->name, &entry->len); error = decode_filename_inline(xdr, &entry->name, &entry->len);
if (unlikely(error)) if (unlikely(error))
return error; return -EAGAIN;
/* /*
* The type (size and byte order) of nfscookie isn't defined in * The type (size and byte order) of nfscookie isn't defined in
* RFC 1094. This implementation assumes that it's an XDR uint32. * RFC 1094. This implementation assumes that it's an XDR uint32.
*/ */
entry->prev_cookie = entry->cookie;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
return -EAGAIN; return -EAGAIN;
......
...@@ -1261,6 +1261,8 @@ static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, ...@@ -1261,6 +1261,8 @@ static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
static void encode_readdirplus3args(struct xdr_stream *xdr, static void encode_readdirplus3args(struct xdr_stream *xdr,
const struct nfs3_readdirargs *args) const struct nfs3_readdirargs *args)
{ {
uint32_t dircount = args->count;
uint32_t maxcount = args->count;
__be32 *p; __be32 *p;
encode_nfs_fh3(xdr, args->fh); encode_nfs_fh3(xdr, args->fh);
...@@ -1273,9 +1275,8 @@ static void encode_readdirplus3args(struct xdr_stream *xdr, ...@@ -1273,9 +1275,8 @@ static void encode_readdirplus3args(struct xdr_stream *xdr,
* readdirplus: need dircount + buffer size. * readdirplus: need dircount + buffer size.
* We just make sure we make dircount big enough * We just make sure we make dircount big enough
*/ */
*p++ = cpu_to_be32(args->count >> 3); *p++ = cpu_to_be32(dircount);
*p = cpu_to_be32(maxcount);
*p = cpu_to_be32(args->count);
} }
static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
...@@ -1967,7 +1968,6 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -1967,7 +1968,6 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
bool plus) bool plus)
{ {
struct user_namespace *userns = rpc_userns(entry->server->client); struct user_namespace *userns = rpc_userns(entry->server->client);
struct nfs_entry old = *entry;
__be32 *p; __be32 *p;
int error; int error;
u64 new_cookie; u64 new_cookie;
...@@ -1987,15 +1987,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -1987,15 +1987,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
error = decode_fileid3(xdr, &entry->ino); error = decode_fileid3(xdr, &entry->ino);
if (unlikely(error)) if (unlikely(error))
return error; return -EAGAIN;
error = decode_inline_filename3(xdr, &entry->name, &entry->len); error = decode_inline_filename3(xdr, &entry->name, &entry->len);
if (unlikely(error)) if (unlikely(error))
return error; return -EAGAIN;
error = decode_cookie3(xdr, &new_cookie); error = decode_cookie3(xdr, &new_cookie);
if (unlikely(error)) if (unlikely(error))
return error; return -EAGAIN;
entry->d_type = DT_UNKNOWN; entry->d_type = DT_UNKNOWN;
...@@ -2003,7 +2003,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -2003,7 +2003,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
entry->fattr->valid = 0; entry->fattr->valid = 0;
error = decode_post_op_attr(xdr, entry->fattr, userns); error = decode_post_op_attr(xdr, entry->fattr, userns);
if (unlikely(error)) if (unlikely(error))
return error; return -EAGAIN;
if (entry->fattr->valid & NFS_ATTR_FATTR_V3) if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
...@@ -2018,24 +2018,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -2018,24 +2018,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
return -EAGAIN; return -EAGAIN;
if (*p != xdr_zero) { if (*p != xdr_zero) {
error = decode_nfs_fh3(xdr, entry->fh); error = decode_nfs_fh3(xdr, entry->fh);
if (unlikely(error)) { if (unlikely(error))
if (error == -E2BIG) return -EAGAIN;
goto out_truncated;
return error;
}
} else } else
zero_nfs_fh3(entry->fh); zero_nfs_fh3(entry->fh);
} }
entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie; entry->cookie = new_cookie;
return 0; return 0;
out_truncated:
dprintk("NFS: directory entry contains invalid file handle\n");
*entry = old;
return -EAGAIN;
} }
/* /*
...@@ -2228,6 +2219,7 @@ static int decode_fsinfo3resok(struct xdr_stream *xdr, ...@@ -2228,6 +2219,7 @@ static int decode_fsinfo3resok(struct xdr_stream *xdr,
/* ignore properties */ /* ignore properties */
result->lease_time = 0; result->lease_time = 0;
result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED; result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
result->xattr_support = 0;
return 0; return 0;
} }
......
...@@ -175,28 +175,27 @@ static int handle_async_copy(struct nfs42_copy_res *res, ...@@ -175,28 +175,27 @@ static int handle_async_copy(struct nfs42_copy_res *res,
nfs4_stateid *src_stateid, nfs4_stateid *src_stateid,
bool *restart) bool *restart)
{ {
struct nfs4_copy_state *copy, *tmp_copy; struct nfs4_copy_state *copy, *tmp_copy = NULL, *iter;
int status = NFS4_OK; int status = NFS4_OK;
bool found_pending = false;
struct nfs_open_context *dst_ctx = nfs_file_open_context(dst); struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
struct nfs_open_context *src_ctx = nfs_file_open_context(src); struct nfs_open_context *src_ctx = nfs_file_open_context(src);
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL);
if (!copy) if (!copy)
return -ENOMEM; return -ENOMEM;
spin_lock(&dst_server->nfs_client->cl_lock); spin_lock(&dst_server->nfs_client->cl_lock);
list_for_each_entry(tmp_copy, list_for_each_entry(iter,
&dst_server->nfs_client->pending_cb_stateids, &dst_server->nfs_client->pending_cb_stateids,
copies) { copies) {
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid, if (memcmp(&res->write_res.stateid, &iter->stateid,
NFS4_STATEID_SIZE)) NFS4_STATEID_SIZE))
continue; continue;
found_pending = true; tmp_copy = iter;
list_del(&tmp_copy->copies); list_del(&iter->copies);
break; break;
} }
if (found_pending) { if (tmp_copy) {
spin_unlock(&dst_server->nfs_client->cl_lock); spin_unlock(&dst_server->nfs_client->cl_lock);
kfree(copy); kfree(copy);
copy = tmp_copy; copy = tmp_copy;
...@@ -254,7 +253,7 @@ static int process_copy_commit(struct file *dst, loff_t pos_dst, ...@@ -254,7 +253,7 @@ static int process_copy_commit(struct file *dst, loff_t pos_dst,
struct nfs_commitres cres; struct nfs_commitres cres;
int status = -ENOMEM; int status = -ENOMEM;
cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_KERNEL);
if (!cres.verf) if (!cres.verf)
goto out; goto out;
...@@ -357,7 +356,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, ...@@ -357,7 +356,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
res->commit_res.verf = NULL; res->commit_res.verf = NULL;
if (args->sync) { if (args->sync) {
res->commit_res.verf = res->commit_res.verf =
kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); kzalloc(sizeof(struct nfs_writeverf), GFP_KERNEL);
if (!res->commit_res.verf) if (!res->commit_res.verf)
return -ENOMEM; return -ENOMEM;
} }
...@@ -552,7 +551,7 @@ static int nfs42_do_offload_cancel_async(struct file *dst, ...@@ -552,7 +551,7 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL)) if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS); data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_KERNEL);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -591,8 +590,10 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst, ...@@ -591,8 +590,10 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
ctx = get_nfs_open_context(nfs_file_open_context(src)); ctx = get_nfs_open_context(nfs_file_open_context(src));
l_ctx = nfs_get_lock_context(ctx); l_ctx = nfs_get_lock_context(ctx);
if (IS_ERR(l_ctx)) if (IS_ERR(l_ctx)) {
return PTR_ERR(l_ctx); status = PTR_ERR(l_ctx);
goto out;
}
status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx, status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
FMODE_READ); FMODE_READ);
...@@ -600,7 +601,7 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst, ...@@ -600,7 +601,7 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
if (status) { if (status) {
if (status == -EAGAIN) if (status == -EAGAIN)
status = -NFS4ERR_BAD_STATEID; status = -NFS4ERR_BAD_STATEID;
return status; goto out;
} }
status = nfs4_call_sync(src_server->client, src_server, &msg, status = nfs4_call_sync(src_server->client, src_server, &msg,
...@@ -609,6 +610,7 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst, ...@@ -609,6 +610,7 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
if (status == -ENOTSUPP) if (status == -ENOTSUPP)
src_server->caps &= ~NFS_CAP_COPY_NOTIFY; src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
out:
put_nfs_open_context(nfs_file_open_context(src)); put_nfs_open_context(nfs_file_open_context(src));
return status; return status;
} }
...@@ -626,7 +628,7 @@ int nfs42_proc_copy_notify(struct file *src, struct file *dst, ...@@ -626,7 +628,7 @@ int nfs42_proc_copy_notify(struct file *src, struct file *dst,
if (!(src_server->caps & NFS_CAP_COPY_NOTIFY)) if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
return -EOPNOTSUPP; return -EOPNOTSUPP;
args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS); args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_KERNEL);
if (args == NULL) if (args == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1014,7 +1016,7 @@ int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg, ...@@ -1014,7 +1016,7 @@ int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (n > NFS42_LAYOUTERROR_MAX) if (n > NFS42_LAYOUTERROR_MAX)
return -EINVAL; return -EINVAL;
data = nfs42_alloc_layouterror_data(lseg, GFP_NOFS); data = nfs42_alloc_layouterror_data(lseg, nfs_io_gfp_mask());
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
......
...@@ -199,7 +199,7 @@ nfs4_xattr_alloc_entry(const char *name, const void *value, ...@@ -199,7 +199,7 @@ nfs4_xattr_alloc_entry(const char *name, const void *value,
flags = NFS4_XATTR_ENTRY_EXTVAL; flags = NFS4_XATTR_ENTRY_EXTVAL;
} }
buf = kmalloc(alloclen, GFP_KERNEL_ACCOUNT | GFP_NOFS); buf = kmalloc(alloclen, GFP_KERNEL);
if (buf == NULL) if (buf == NULL)
return NULL; return NULL;
entry = (struct nfs4_xattr_entry *)buf; entry = (struct nfs4_xattr_entry *)buf;
...@@ -213,7 +213,7 @@ nfs4_xattr_alloc_entry(const char *name, const void *value, ...@@ -213,7 +213,7 @@ nfs4_xattr_alloc_entry(const char *name, const void *value,
if (flags & NFS4_XATTR_ENTRY_EXTVAL) { if (flags & NFS4_XATTR_ENTRY_EXTVAL) {
valp = kvmalloc(len, GFP_KERNEL_ACCOUNT | GFP_NOFS); valp = kvmalloc(len, GFP_KERNEL);
if (valp == NULL) { if (valp == NULL) {
kfree(buf); kfree(buf);
return NULL; return NULL;
...@@ -289,8 +289,7 @@ nfs4_xattr_alloc_cache(void) ...@@ -289,8 +289,7 @@ nfs4_xattr_alloc_cache(void)
{ {
struct nfs4_xattr_cache *cache; struct nfs4_xattr_cache *cache;
cache = kmem_cache_alloc(nfs4_xattr_cache_cachep, cache = kmem_cache_alloc(nfs4_xattr_cache_cachep, GFP_KERNEL);
GFP_KERNEL_ACCOUNT | GFP_NOFS);
if (cache == NULL) if (cache == NULL)
return NULL; return NULL;
......
...@@ -42,6 +42,7 @@ enum nfs4_client_state { ...@@ -42,6 +42,7 @@ enum nfs4_client_state {
NFS4CLNT_LEASE_MOVED, NFS4CLNT_LEASE_MOVED,
NFS4CLNT_DELEGATION_EXPIRED, NFS4CLNT_DELEGATION_EXPIRED,
NFS4CLNT_RUN_MANAGER, NFS4CLNT_RUN_MANAGER,
NFS4CLNT_MANAGER_AVAILABLE,
NFS4CLNT_RECALL_RUNNING, NFS4CLNT_RECALL_RUNNING,
NFS4CLNT_RECALL_ANY_LAYOUT_READ, NFS4CLNT_RECALL_ANY_LAYOUT_READ,
NFS4CLNT_RECALL_ANY_LAYOUT_RW, NFS4CLNT_RECALL_ANY_LAYOUT_RW,
......
...@@ -165,7 +165,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in, ...@@ -165,7 +165,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
if (sync) if (sync)
return -EOPNOTSUPP; return -EOPNOTSUPP;
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res), cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
GFP_NOFS); GFP_KERNEL);
if (unlikely(cn_resp == NULL)) if (unlikely(cn_resp == NULL))
return -ENOMEM; return -ENOMEM;
...@@ -180,8 +180,8 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in, ...@@ -180,8 +180,8 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count, ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count,
nss, cnrs, sync); nss, cnrs, sync);
out: out:
if (!nfs42_files_from_same_server(file_in, file_out))
kfree(cn_resp); kfree(cn_resp);
if (ret == -EAGAIN) if (ret == -EAGAIN)
goto retry; goto retry;
return ret; return ret;
...@@ -339,7 +339,7 @@ static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt, ...@@ -339,7 +339,7 @@ static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
res = ERR_PTR(-ENOMEM); res = ERR_PTR(-ENOMEM);
len = strlen(SSC_READ_NAME_BODY) + 16; len = strlen(SSC_READ_NAME_BODY) + 16;
read_name = kzalloc(len, GFP_NOFS); read_name = kzalloc(len, GFP_KERNEL);
if (read_name == NULL) if (read_name == NULL)
goto out; goto out;
snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++); snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);
......
...@@ -1392,13 +1392,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -1392,13 +1392,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
case NFS4_OPEN_CLAIM_FH: case NFS4_OPEN_CLAIM_FH:
p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY | p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE |
NFS4_ACCESS_EXECUTE; NFS4_ACCESS_EXECUTE |
#ifdef CONFIG_NFS_V4_2 nfs_access_xattr_mask(server);
if (!(server->caps & NFS_CAP_XATTR))
break;
p->o_arg.access |= NFS4_ACCESS_XAREAD | NFS4_ACCESS_XAWRITE |
NFS4_ACCESS_XALIST;
#endif
} }
p->o_arg.clientid = server->nfs_client->cl_clientid; p->o_arg.clientid = server->nfs_client->cl_clientid;
p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time); p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
...@@ -3050,6 +3045,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, ...@@ -3050,6 +3045,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK) if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK)
set_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags); set_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags);
if (opendata->o_res.rflags & NFS4_OPEN_RESULT_PRESERVE_UNLINKED)
set_bit(NFS_INO_PRESERVE_UNLINKED, &NFS_I(state->inode)->flags);
dentry = opendata->dentry; dentry = opendata->dentry;
if (d_really_is_negative(dentry)) { if (d_really_is_negative(dentry)) {
...@@ -5904,7 +5901,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -5904,7 +5901,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
buflen = server->rsize; buflen = server->rsize;
npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1; npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
pages = kmalloc_array(npages, sizeof(struct page *), GFP_NOFS); pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
if (!pages) if (!pages)
return -ENOMEM; return -ENOMEM;
...@@ -6609,7 +6606,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, ...@@ -6609,7 +6606,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
}; };
int status = 0; int status = 0;
data = kzalloc(sizeof(*data), GFP_NOFS); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -6797,7 +6794,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, ...@@ -6797,7 +6794,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
struct nfs4_state *state = lsp->ls_state; struct nfs4_state *state = lsp->ls_state;
struct inode *inode = state->inode; struct inode *inode = state->inode;
p = kzalloc(sizeof(*p), GFP_NOFS); p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL) if (p == NULL)
return NULL; return NULL;
p->arg.fh = NFS_FH(inode); p->arg.fh = NFS_FH(inode);
...@@ -7202,8 +7199,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f ...@@ -7202,8 +7199,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
task_setup_data.flags |= RPC_TASK_MOVEABLE; task_setup_data.flags |= RPC_TASK_MOVEABLE;
data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
fl->fl_u.nfs4_fl.owner, fl->fl_u.nfs4_fl.owner, GFP_KERNEL);
recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
if (IS_SETLKW(cmd)) if (IS_SETLKW(cmd))
...@@ -7626,7 +7622,7 @@ nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp) ...@@ -7626,7 +7622,7 @@ nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
if (server->nfs_client->cl_mvops->minor_version != 0) if (server->nfs_client->cl_mvops->minor_version != 0)
return; return;
data = kmalloc(sizeof(*data), GFP_NOFS); data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return; return;
data->lsp = lsp; data->lsp = lsp;
...@@ -8012,6 +8008,18 @@ static int _nfs41_proc_get_locations(struct nfs_server *server, ...@@ -8012,6 +8008,18 @@ static int _nfs41_proc_get_locations(struct nfs_server *server,
.rpc_resp = &res, .rpc_resp = &res,
.rpc_cred = cred, .rpc_cred = cred,
}; };
struct nfs4_call_sync_data data = {
.seq_server = server,
.seq_args = &args.seq_args,
.seq_res = &res.seq_res,
};
struct rpc_task_setup task_setup_data = {
.rpc_client = clnt,
.rpc_message = &msg,
.callback_ops = server->nfs_client->cl_mvops->call_sync_ops,
.callback_data = &data,
.flags = RPC_TASK_NO_ROUND_ROBIN,
};
int status; int status;
nfs_fattr_init(&locations->fattr); nfs_fattr_init(&locations->fattr);
...@@ -8019,8 +8027,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server, ...@@ -8019,8 +8027,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server,
locations->nlocations = 0; locations->nlocations = 0;
nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1); nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
status = nfs4_call_sync_sequence(clnt, server, &msg, status = nfs4_call_sync_custom(&task_setup_data);
&args.seq_args, &res.seq_res);
if (status == NFS4_OK && if (status == NFS4_OK &&
res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED) res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
status = -NFS4ERR_LEASE_MOVED; status = -NFS4ERR_LEASE_MOVED;
...@@ -8333,6 +8340,7 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata) ...@@ -8333,6 +8340,7 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
case -NFS4ERR_DEADSESSION: case -NFS4ERR_DEADSESSION:
nfs4_schedule_session_recovery(clp->cl_session, nfs4_schedule_session_recovery(clp->cl_session,
task->tk_status); task->tk_status);
return;
} }
if (args->dir == NFS4_CDFC4_FORE_OR_BOTH && if (args->dir == NFS4_CDFC4_FORE_OR_BOTH &&
res->dir != NFS4_CDFS4_BOTH) { res->dir != NFS4_CDFS4_BOTH) {
...@@ -9291,7 +9299,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, ...@@ -9291,7 +9299,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
goto out_err; goto out_err;
ret = ERR_PTR(-ENOMEM); ret = ERR_PTR(-ENOMEM);
calldata = kzalloc(sizeof(*calldata), GFP_NOFS); calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
if (calldata == NULL) if (calldata == NULL)
goto out_put_clp; goto out_put_clp;
nfs4_init_sequence(&calldata->args, &calldata->res, 0, is_privileged); nfs4_init_sequence(&calldata->args, &calldata->res, 0, is_privileged);
...@@ -10222,7 +10230,7 @@ static int nfs41_free_stateid(struct nfs_server *server, ...@@ -10222,7 +10230,7 @@ static int nfs41_free_stateid(struct nfs_server *server,
&task_setup.rpc_client, &msg); &task_setup.rpc_client, &msg);
dprintk("NFS call free_stateid %p\n", stateid); dprintk("NFS call free_stateid %p\n", stateid);
data = kmalloc(sizeof(*data), GFP_NOFS); data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
data->server = server; data->server = server;
...@@ -10461,6 +10469,24 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size) ...@@ -10461,6 +10469,24 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
return error + error2 + error3; return error + error2 + error3;
} }
static void nfs4_enable_swap(struct inode *inode)
{
/* The state manager thread must always be running.
* It will notice the client is a swapper, and stay put.
*/
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
nfs4_schedule_state_manager(clp);
}
static void nfs4_disable_swap(struct inode *inode)
{
/* The state manager thread will now exit once it is
* woken.
*/
wake_up_var(&NFS_SERVER(inode)->nfs_client->cl_state);
}
static const struct inode_operations nfs4_dir_inode_operations = { static const struct inode_operations nfs4_dir_inode_operations = {
.create = nfs_create, .create = nfs_create,
.lookup = nfs_lookup, .lookup = nfs_lookup,
...@@ -10538,6 +10564,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = { ...@@ -10538,6 +10564,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.create_server = nfs4_create_server, .create_server = nfs4_create_server,
.clone_server = nfs_clone_server, .clone_server = nfs_clone_server,
.discover_trunking = nfs4_discover_trunking, .discover_trunking = nfs4_discover_trunking,
.enable_swap = nfs4_enable_swap,
.disable_swap = nfs4_disable_swap,
}; };
static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/sched/mm.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
...@@ -666,7 +667,7 @@ nfs4_alloc_open_state(void) ...@@ -666,7 +667,7 @@ nfs4_alloc_open_state(void)
{ {
struct nfs4_state *state; struct nfs4_state *state;
state = kzalloc(sizeof(*state), GFP_NOFS); state = kzalloc(sizeof(*state), GFP_KERNEL_ACCOUNT);
if (!state) if (!state)
return NULL; return NULL;
refcount_set(&state->count, 1); refcount_set(&state->count, 1);
...@@ -820,7 +821,7 @@ static void __nfs4_close(struct nfs4_state *state, ...@@ -820,7 +821,7 @@ static void __nfs4_close(struct nfs4_state *state,
void nfs4_close_state(struct nfs4_state *state, fmode_t fmode) void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
{ {
__nfs4_close(state, fmode, GFP_NOFS, 0); __nfs4_close(state, fmode, GFP_KERNEL, 0);
} }
void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode) void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
...@@ -869,14 +870,15 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f ...@@ -869,14 +870,15 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
struct nfs4_lock_state *lsp; struct nfs4_lock_state *lsp;
struct nfs_server *server = state->owner->so_server; struct nfs_server *server = state->owner->so_server;
lsp = kzalloc(sizeof(*lsp), GFP_NOFS); lsp = kzalloc(sizeof(*lsp), GFP_KERNEL_ACCOUNT);
if (lsp == NULL) if (lsp == NULL)
return NULL; return NULL;
nfs4_init_seqid_counter(&lsp->ls_seqid); nfs4_init_seqid_counter(&lsp->ls_seqid);
refcount_set(&lsp->ls_count, 1); refcount_set(&lsp->ls_count, 1);
lsp->ls_state = state; lsp->ls_state = state;
lsp->ls_owner = fl_owner; lsp->ls_owner = fl_owner;
lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS); lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id,
0, 0, GFP_KERNEL_ACCOUNT);
if (lsp->ls_seqid.owner_id < 0) if (lsp->ls_seqid.owner_id < 0)
goto out_free; goto out_free;
INIT_LIST_HEAD(&lsp->ls_locks); INIT_LIST_HEAD(&lsp->ls_locks);
...@@ -1205,10 +1207,17 @@ void nfs4_schedule_state_manager(struct nfs_client *clp) ...@@ -1205,10 +1207,17 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
{ {
struct task_struct *task; struct task_struct *task;
char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
struct rpc_clnt *cl = clp->cl_rpcclient;
while (cl != cl->cl_parent)
cl = cl->cl_parent;
set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state); set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) if (test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state) != 0) {
wake_up_var(&clp->cl_state);
return; return;
}
set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
refcount_inc(&clp->cl_count); refcount_inc(&clp->cl_count);
...@@ -1224,6 +1233,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp) ...@@ -1224,6 +1233,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
printk(KERN_ERR "%s: kthread_run: %ld\n", printk(KERN_ERR "%s: kthread_run: %ld\n",
__func__, PTR_ERR(task)); __func__, PTR_ERR(task));
nfs4_clear_state_manager_bit(clp); nfs4_clear_state_manager_bit(clp);
clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
nfs_put_client(clp); nfs_put_client(clp);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
...@@ -2560,9 +2570,17 @@ static void nfs4_layoutreturn_any_run(struct nfs_client *clp) ...@@ -2560,9 +2570,17 @@ static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
static void nfs4_state_manager(struct nfs_client *clp) static void nfs4_state_manager(struct nfs_client *clp)
{ {
unsigned int memflags;
int status = 0; int status = 0;
const char *section = "", *section_sep = ""; const char *section = "", *section_sep = "";
/*
* State recovery can deadlock if the direct reclaim code tries
* start NFS writeback. So ensure memory allocations are all
* GFP_NOFS.
*/
memflags = memalloc_nofs_save();
/* Ensure exclusive access to NFSv4 state */ /* Ensure exclusive access to NFSv4 state */
do { do {
trace_nfs4_state_mgr(clp); trace_nfs4_state_mgr(clp);
...@@ -2657,6 +2675,7 @@ static void nfs4_state_manager(struct nfs_client *clp) ...@@ -2657,6 +2675,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
} }
memalloc_nofs_restore(memflags);
nfs4_end_drain_session(clp); nfs4_end_drain_session(clp);
nfs4_clear_state_manager_bit(clp); nfs4_clear_state_manager_bit(clp);
...@@ -2669,11 +2688,8 @@ static void nfs4_state_manager(struct nfs_client *clp) ...@@ -2669,11 +2688,8 @@ static void nfs4_state_manager(struct nfs_client *clp)
clear_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state); clear_bit(NFS4CLNT_RECALL_RUNNING, &clp->cl_state);
} }
/* Did we race with an attempt to give us more work? */
if (!test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
return;
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
return; return;
} while (refcount_read(&clp->cl_count) > 1 && !signalled()); } while (refcount_read(&clp->cl_count) > 1 && !signalled());
goto out_drain; goto out_drain;
...@@ -2686,6 +2702,7 @@ static void nfs4_state_manager(struct nfs_client *clp) ...@@ -2686,6 +2702,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
clp->cl_hostname, -status); clp->cl_hostname, -status);
ssleep(1); ssleep(1);
out_drain: out_drain:
memalloc_nofs_restore(memflags);
nfs4_end_drain_session(clp); nfs4_end_drain_session(clp);
nfs4_clear_state_manager_bit(clp); nfs4_clear_state_manager_bit(clp);
} }
...@@ -2693,9 +2710,31 @@ static void nfs4_state_manager(struct nfs_client *clp) ...@@ -2693,9 +2710,31 @@ static void nfs4_state_manager(struct nfs_client *clp)
static int nfs4_run_state_manager(void *ptr) static int nfs4_run_state_manager(void *ptr)
{ {
struct nfs_client *clp = ptr; struct nfs_client *clp = ptr;
struct rpc_clnt *cl = clp->cl_rpcclient;
while (cl != cl->cl_parent)
cl = cl->cl_parent;
allow_signal(SIGKILL); allow_signal(SIGKILL);
again:
set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
nfs4_state_manager(clp); nfs4_state_manager(clp);
if (atomic_read(&cl->cl_swapper)) {
wait_var_event_interruptible(&clp->cl_state,
test_bit(NFS4CLNT_RUN_MANAGER,
&clp->cl_state));
if (atomic_read(&cl->cl_swapper) &&
test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state))
goto again;
/* Either no longer a swapper, or were signalled */
}
clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
if (refcount_read(&clp->cl_count) > 1 && !signalled() &&
test_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state) &&
!test_and_set_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state))
goto again;
nfs_put_client(clp); nfs_put_client(clp);
return 0; return 0;
} }
...@@ -1605,7 +1605,8 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg ...@@ -1605,7 +1605,8 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
FATTR4_WORD0_RDATTR_ERROR, FATTR4_WORD0_RDATTR_ERROR,
FATTR4_WORD1_MOUNTED_ON_FILEID, FATTR4_WORD1_MOUNTED_ON_FILEID,
}; };
uint32_t dircount = readdir->count >> 1; uint32_t dircount = readdir->count;
uint32_t maxcount = readdir->count;
__be32 *p, verf[2]; __be32 *p, verf[2];
uint32_t attrlen = 0; uint32_t attrlen = 0;
unsigned int i; unsigned int i;
...@@ -1618,7 +1619,6 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg ...@@ -1618,7 +1619,6 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
attrs[2] |= FATTR4_WORD2_SECURITY_LABEL; attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
dircount >>= 1;
} }
/* Use mounted_on_fileid only if the server supports it */ /* Use mounted_on_fileid only if the server supports it */
if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
...@@ -1634,7 +1634,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg ...@@ -1634,7 +1634,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
encode_nfs4_verifier(xdr, &readdir->verifier); encode_nfs4_verifier(xdr, &readdir->verifier);
p = reserve_space(xdr, 12 + (attrlen << 2)); p = reserve_space(xdr, 12 + (attrlen << 2));
*p++ = cpu_to_be32(dircount); *p++ = cpu_to_be32(dircount);
*p++ = cpu_to_be32(readdir->count); *p++ = cpu_to_be32(maxcount);
*p++ = cpu_to_be32(attrlen); *p++ = cpu_to_be32(attrlen);
for (i = 0; i < attrlen; i++) for (i = 0; i < attrlen; i++)
*p++ = cpu_to_be32(attrs[i]); *p++ = cpu_to_be32(attrs[i]);
...@@ -7508,7 +7508,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -7508,7 +7508,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie; entry->cookie = new_cookie;
return 0; return 0;
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
{ NFS_INO_INVALID_ATIME, "INVALID_ATIME" }, \ { NFS_INO_INVALID_ATIME, "INVALID_ATIME" }, \
{ NFS_INO_INVALID_ACCESS, "INVALID_ACCESS" }, \ { NFS_INO_INVALID_ACCESS, "INVALID_ACCESS" }, \
{ NFS_INO_INVALID_ACL, "INVALID_ACL" }, \ { NFS_INO_INVALID_ACL, "INVALID_ACL" }, \
{ NFS_INO_REVAL_PAGECACHE, "REVAL_PAGECACHE" }, \
{ NFS_INO_REVAL_FORCED, "REVAL_FORCED" }, \ { NFS_INO_REVAL_FORCED, "REVAL_FORCED" }, \
{ NFS_INO_INVALID_LABEL, "INVALID_LABEL" }, \ { NFS_INO_INVALID_LABEL, "INVALID_LABEL" }, \
{ NFS_INO_INVALID_CHANGE, "INVALID_CHANGE" }, \ { NFS_INO_INVALID_CHANGE, "INVALID_CHANGE" }, \
...@@ -37,7 +36,6 @@ ...@@ -37,7 +36,6 @@
#define nfs_show_nfsi_flags(v) \ #define nfs_show_nfsi_flags(v) \
__print_flags(v, "|", \ __print_flags(v, "|", \
{ BIT(NFS_INO_ADVISE_RDPLUS), "ADVISE_RDPLUS" }, \
{ BIT(NFS_INO_STALE), "STALE" }, \ { BIT(NFS_INO_STALE), "STALE" }, \
{ BIT(NFS_INO_ACL_LRU_SET), "ACL_LRU_SET" }, \ { BIT(NFS_INO_ACL_LRU_SET), "ACL_LRU_SET" }, \
{ BIT(NFS_INO_INVALIDATING), "INVALIDATING" }, \ { BIT(NFS_INO_INVALIDATING), "INVALIDATING" }, \
...@@ -162,6 +160,9 @@ DEFINE_NFS_INODE_EVENT(nfs_fsync_enter); ...@@ -162,6 +160,9 @@ DEFINE_NFS_INODE_EVENT(nfs_fsync_enter);
DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit); DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit);
DEFINE_NFS_INODE_EVENT(nfs_access_enter); DEFINE_NFS_INODE_EVENT(nfs_access_enter);
DEFINE_NFS_INODE_EVENT_DONE(nfs_set_cache_invalid); DEFINE_NFS_INODE_EVENT_DONE(nfs_set_cache_invalid);
DEFINE_NFS_INODE_EVENT(nfs_readdir_force_readdirplus);
DEFINE_NFS_INODE_EVENT_DONE(nfs_readdir_cache_fill_done);
DEFINE_NFS_INODE_EVENT_DONE(nfs_readdir_uncached_done);
TRACE_EVENT(nfs_access_exit, TRACE_EVENT(nfs_access_exit,
TP_PROTO( TP_PROTO(
...@@ -273,6 +274,122 @@ DEFINE_NFS_UPDATE_SIZE_EVENT(wcc); ...@@ -273,6 +274,122 @@ DEFINE_NFS_UPDATE_SIZE_EVENT(wcc);
DEFINE_NFS_UPDATE_SIZE_EVENT(update); DEFINE_NFS_UPDATE_SIZE_EVENT(update);
DEFINE_NFS_UPDATE_SIZE_EVENT(grow); DEFINE_NFS_UPDATE_SIZE_EVENT(grow);
DECLARE_EVENT_CLASS(nfs_inode_range_event,
TP_PROTO(
const struct inode *inode,
loff_t range_start,
loff_t range_end
),
TP_ARGS(inode, range_start, range_end),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
__field(u64, version)
__field(loff_t, range_start)
__field(loff_t, range_end)
),
TP_fast_assign(
const struct nfs_inode *nfsi = NFS_I(inode);
__entry->dev = inode->i_sb->s_dev;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->fileid = nfsi->fileid;
__entry->version = inode_peek_iversion_raw(inode);
__entry->range_start = range_start;
__entry->range_end = range_end;
),
TP_printk(
"fileid=%02x:%02x:%llu fhandle=0x%08x version=%llu "
"range=[%lld, %lld]",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle, __entry->version,
__entry->range_start, __entry->range_end
)
);
#define DEFINE_NFS_INODE_RANGE_EVENT(name) \
DEFINE_EVENT(nfs_inode_range_event, name, \
TP_PROTO( \
const struct inode *inode, \
loff_t range_start, \
loff_t range_end \
), \
TP_ARGS(inode, range_start, range_end))
DEFINE_NFS_INODE_RANGE_EVENT(nfs_readdir_invalidate_cache_range);
DECLARE_EVENT_CLASS(nfs_readdir_event,
TP_PROTO(
const struct file *file,
const __be32 *verifier,
u64 cookie,
pgoff_t page_index,
unsigned int dtsize
),
TP_ARGS(file, verifier, cookie, page_index, dtsize),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
__field(u64, version)
__array(char, verifier, NFS4_VERIFIER_SIZE)
__field(u64, cookie)
__field(pgoff_t, index)
__field(unsigned int, dtsize)
),
TP_fast_assign(
const struct inode *dir = file_inode(file);
const struct nfs_inode *nfsi = NFS_I(dir);
__entry->dev = dir->i_sb->s_dev;
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->version = inode_peek_iversion_raw(dir);
if (cookie != 0)
memcpy(__entry->verifier, verifier,
NFS4_VERIFIER_SIZE);
else
memset(__entry->verifier, 0,
NFS4_VERIFIER_SIZE);
__entry->cookie = cookie;
__entry->index = page_index;
__entry->dtsize = dtsize;
),
TP_printk(
"fileid=%02x:%02x:%llu fhandle=0x%08x version=%llu "
"cookie=%s:0x%llx cache_index=%lu dtsize=%u",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid, __entry->fhandle,
__entry->version, show_nfs4_verifier(__entry->verifier),
(unsigned long long)__entry->cookie, __entry->index,
__entry->dtsize
)
);
#define DEFINE_NFS_READDIR_EVENT(name) \
DEFINE_EVENT(nfs_readdir_event, name, \
TP_PROTO( \
const struct file *file, \
const __be32 *verifier, \
u64 cookie, \
pgoff_t page_index, \
unsigned int dtsize \
), \
TP_ARGS(file, verifier, cookie, page_index, dtsize))
DEFINE_NFS_READDIR_EVENT(nfs_readdir_cache_fill);
DEFINE_NFS_READDIR_EVENT(nfs_readdir_uncached);
DECLARE_EVENT_CLASS(nfs_lookup_event, DECLARE_EVENT_CLASS(nfs_lookup_event,
TP_PROTO( TP_PROTO(
const struct inode *dir, const struct inode *dir,
...@@ -366,6 +483,9 @@ DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_enter); ...@@ -366,6 +483,9 @@ DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_enter);
DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_exit); DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_exit);
DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_revalidate_enter); DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_revalidate_enter);
DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_revalidate_exit); DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_revalidate_exit);
DEFINE_NFS_LOOKUP_EVENT(nfs_readdir_lookup);
DEFINE_NFS_LOOKUP_EVENT(nfs_readdir_lookup_revalidate_failed);
DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_readdir_lookup_revalidate);
TRACE_EVENT(nfs_atomic_open_enter, TRACE_EVENT(nfs_atomic_open_enter,
TP_PROTO( TP_PROTO(
...@@ -889,11 +1009,11 @@ TRACE_EVENT(nfs_aop_readpage_done, ...@@ -889,11 +1009,11 @@ TRACE_EVENT(nfs_aop_readpage_done,
TRACE_EVENT(nfs_aop_readahead, TRACE_EVENT(nfs_aop_readahead,
TP_PROTO( TP_PROTO(
const struct inode *inode, const struct inode *inode,
struct page *page, loff_t pos,
unsigned int nr_pages unsigned int nr_pages
), ),
TP_ARGS(inode, page, nr_pages), TP_ARGS(inode, pos, nr_pages),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
...@@ -911,7 +1031,7 @@ TRACE_EVENT(nfs_aop_readahead, ...@@ -911,7 +1031,7 @@ TRACE_EVENT(nfs_aop_readahead,
__entry->fileid = nfsi->fileid; __entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh); __entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->version = inode_peek_iversion_raw(inode); __entry->version = inode_peek_iversion_raw(inode);
__entry->offset = page_index(page) << PAGE_SHIFT; __entry->offset = pos;
__entry->nr_pages = nr_pages; __entry->nr_pages = nr_pages;
), ),
...@@ -1095,6 +1215,97 @@ TRACE_EVENT(nfs_readpage_short, ...@@ -1095,6 +1215,97 @@ TRACE_EVENT(nfs_readpage_short,
) )
); );
DECLARE_EVENT_CLASS(nfs_fscache_page_event,
TP_PROTO(
const struct inode *inode,
struct page *page
),
TP_ARGS(inode, page),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
__field(loff_t, offset)
),
TP_fast_assign(
const struct nfs_inode *nfsi = NFS_I(inode);
const struct nfs_fh *fh = &nfsi->fh;
__entry->offset = page_index(page) << PAGE_SHIFT;
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(fh);
),
TP_printk(
"fileid=%02x:%02x:%llu fhandle=0x%08x "
"offset=%lld",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle,
(long long)__entry->offset
)
);
DECLARE_EVENT_CLASS(nfs_fscache_page_event_done,
TP_PROTO(
const struct inode *inode,
struct page *page,
int error
),
TP_ARGS(inode, page, error),
TP_STRUCT__entry(
__field(int, error)
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
__field(loff_t, offset)
),
TP_fast_assign(
const struct nfs_inode *nfsi = NFS_I(inode);
const struct nfs_fh *fh = &nfsi->fh;
__entry->offset = page_index(page) << PAGE_SHIFT;
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(fh);
__entry->error = error;
),
TP_printk(
"fileid=%02x:%02x:%llu fhandle=0x%08x "
"offset=%lld error=%d",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle,
(long long)__entry->offset, __entry->error
)
);
#define DEFINE_NFS_FSCACHE_PAGE_EVENT(name) \
DEFINE_EVENT(nfs_fscache_page_event, name, \
TP_PROTO( \
const struct inode *inode, \
struct page *page \
), \
TP_ARGS(inode, page))
#define DEFINE_NFS_FSCACHE_PAGE_EVENT_DONE(name) \
DEFINE_EVENT(nfs_fscache_page_event_done, name, \
TP_PROTO( \
const struct inode *inode, \
struct page *page, \
int error \
), \
TP_ARGS(inode, page, error))
DEFINE_NFS_FSCACHE_PAGE_EVENT(nfs_fscache_read_page);
DEFINE_NFS_FSCACHE_PAGE_EVENT_DONE(nfs_fscache_read_page_exit);
DEFINE_NFS_FSCACHE_PAGE_EVENT(nfs_fscache_write_page);
DEFINE_NFS_FSCACHE_PAGE_EVENT_DONE(nfs_fscache_write_page_exit);
TRACE_EVENT(nfs_pgio_error, TRACE_EVENT(nfs_pgio_error,
TP_PROTO( TP_PROTO(
const struct nfs_pgio_header *hdr, const struct nfs_pgio_header *hdr,
......
...@@ -90,10 +90,10 @@ void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos) ...@@ -90,10 +90,10 @@ void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos)
} }
} }
static inline struct nfs_page * static inline struct nfs_page *nfs_page_alloc(void)
nfs_page_alloc(void)
{ {
struct nfs_page *p = kmem_cache_zalloc(nfs_page_cachep, GFP_KERNEL); struct nfs_page *p =
kmem_cache_zalloc(nfs_page_cachep, nfs_io_gfp_mask());
if (p) if (p)
INIT_LIST_HEAD(&p->wb_list); INIT_LIST_HEAD(&p->wb_list);
return p; return p;
...@@ -892,7 +892,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, ...@@ -892,7 +892,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
struct nfs_page_array *pg_array = &hdr->page_array; struct nfs_page_array *pg_array = &hdr->page_array;
unsigned int pagecount, pageused; unsigned int pagecount, pageused;
gfp_t gfp_flags = GFP_KERNEL; gfp_t gfp_flags = nfs_io_gfp_mask();
pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count); pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count);
pg_array->npages = pagecount; pg_array->npages = pagecount;
...@@ -979,7 +979,7 @@ nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc, ...@@ -979,7 +979,7 @@ nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc,
desc->pg_mirrors_dynamic = NULL; desc->pg_mirrors_dynamic = NULL;
if (mirror_count == 1) if (mirror_count == 1)
return desc->pg_mirrors_static; return desc->pg_mirrors_static;
ret = kmalloc_array(mirror_count, sizeof(*ret), GFP_KERNEL); ret = kmalloc_array(mirror_count, sizeof(*ret), nfs_io_gfp_mask());
if (ret != NULL) { if (ret != NULL) {
for (i = 0; i < mirror_count; i++) for (i = 0; i < mirror_count; i++)
nfs_pageio_mirror_init(&ret[i], desc->pg_bsize); nfs_pageio_mirror_init(&ret[i], desc->pg_bsize);
...@@ -1218,6 +1218,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) ...@@ -1218,6 +1218,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
do { do {
list_splice_init(&mirror->pg_list, &head); list_splice_init(&mirror->pg_list, &head);
mirror->pg_recoalesce = 0;
while (!list_empty(&head)) { while (!list_empty(&head)) {
struct nfs_page *req; struct nfs_page *req;
......
...@@ -92,6 +92,17 @@ find_pnfs_driver(u32 id) ...@@ -92,6 +92,17 @@ find_pnfs_driver(u32 id)
return local; return local;
} }
const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id)
{
return find_pnfs_driver(id);
}
void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld)
{
if (ld)
module_put(ld->owner);
}
void void
unset_pnfs_layoutdriver(struct nfs_server *nfss) unset_pnfs_layoutdriver(struct nfs_server *nfss)
{ {
...@@ -1233,7 +1244,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, ...@@ -1233,7 +1244,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo,
int status = 0; int status = 0;
*pcred = NULL; *pcred = NULL;
lrp = kzalloc(sizeof(*lrp), GFP_NOFS); lrp = kzalloc(sizeof(*lrp), nfs_io_gfp_mask());
if (unlikely(lrp == NULL)) { if (unlikely(lrp == NULL)) {
status = -ENOMEM; status = -ENOMEM;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
...@@ -2206,7 +2217,7 @@ _pnfs_grab_empty_layout(struct inode *ino, struct nfs_open_context *ctx) ...@@ -2206,7 +2217,7 @@ _pnfs_grab_empty_layout(struct inode *ino, struct nfs_open_context *ctx)
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
lo = pnfs_find_alloc_layout(ino, ctx, GFP_KERNEL); lo = pnfs_find_alloc_layout(ino, ctx, nfs_io_gfp_mask());
if (!lo) if (!lo)
goto out_unlock; goto out_unlock;
if (!test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) if (!test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))
...@@ -2249,8 +2260,8 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data, ...@@ -2249,8 +2260,8 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data,
lo = _pnfs_grab_empty_layout(ino, ctx); lo = _pnfs_grab_empty_layout(ino, ctx);
if (!lo) if (!lo)
return; return;
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid, lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid, &rng,
&rng, GFP_KERNEL); nfs_io_gfp_mask());
if (!lgp) { if (!lgp) {
pnfs_clear_first_layoutget(lo); pnfs_clear_first_layoutget(lo);
nfs_layoutget_end(lo); nfs_layoutget_end(lo);
...@@ -2275,8 +2286,8 @@ static void _lgopen_prepare_floating(struct nfs4_opendata *data, ...@@ -2275,8 +2286,8 @@ static void _lgopen_prepare_floating(struct nfs4_opendata *data,
}; };
struct nfs4_layoutget *lgp; struct nfs4_layoutget *lgp;
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid, lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid, &rng,
&rng, GFP_KERNEL); nfs_io_gfp_mask());
if (!lgp) if (!lgp)
return; return;
data->lgp = lgp; data->lgp = lgp;
...@@ -2691,13 +2702,11 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r ...@@ -2691,13 +2702,11 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
else else
rd_size = nfs_dreq_bytes_left(pgio->pg_dreq); rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg =
nfs_req_openctx(req), pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req_offset(req), rd_size,
rd_size, IOMODE_READ, false,
IOMODE_READ, nfs_io_gfp_mask());
false,
GFP_KERNEL);
if (IS_ERR(pgio->pg_lseg)) { if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg); pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
...@@ -2718,13 +2727,10 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, ...@@ -2718,13 +2727,10 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
pnfs_generic_pg_check_layout(pgio); pnfs_generic_pg_check_layout(pgio);
pnfs_generic_pg_check_range(pgio, req); pnfs_generic_pg_check_range(pgio, req);
if (pgio->pg_lseg == NULL) { if (pgio->pg_lseg == NULL) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, pgio->pg_lseg =
nfs_req_openctx(req), pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req_offset(req), wb_size, IOMODE_RW,
wb_size, false, nfs_io_gfp_mask());
IOMODE_RW,
false,
GFP_KERNEL);
if (IS_ERR(pgio->pg_lseg)) { if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg); pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL; pgio->pg_lseg = NULL;
...@@ -3183,7 +3189,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -3183,7 +3189,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
status = -ENOMEM; status = -ENOMEM;
/* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
data = kzalloc(sizeof(*data), GFP_NOFS); data = kzalloc(sizeof(*data), nfs_io_gfp_mask());
if (!data) if (!data)
goto clear_layoutcommitting; goto clear_layoutcommitting;
...@@ -3250,7 +3256,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void) ...@@ -3250,7 +3256,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void)
{ {
struct nfs4_threshold *thp; struct nfs4_threshold *thp;
thp = kzalloc(sizeof(*thp), GFP_NOFS); thp = kzalloc(sizeof(*thp), nfs_io_gfp_mask());
if (!thp) { if (!thp) {
dprintk("%s mdsthreshold allocation failed\n", __func__); dprintk("%s mdsthreshold allocation failed\n", __func__);
return NULL; return NULL;
......
...@@ -234,6 +234,8 @@ struct pnfs_devicelist { ...@@ -234,6 +234,8 @@ struct pnfs_devicelist {
extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
extern const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id);
extern void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld);
/* nfs4proc.c */ /* nfs4proc.c */
extern size_t max_response_pages(struct nfs_server *server); extern size_t max_response_pages(struct nfs_server *server);
......
...@@ -419,7 +419,7 @@ static struct nfs_commit_data * ...@@ -419,7 +419,7 @@ static struct nfs_commit_data *
pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket, pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket,
struct nfs_commit_info *cinfo) struct nfs_commit_info *cinfo)
{ {
struct nfs_commit_data *data = nfs_commitdata_alloc(false); struct nfs_commit_data *data = nfs_commitdata_alloc();
if (!data) if (!data)
return NULL; return NULL;
...@@ -515,7 +515,11 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages, ...@@ -515,7 +515,11 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
unsigned int nreq = 0; unsigned int nreq = 0;
if (!list_empty(mds_pages)) { if (!list_empty(mds_pages)) {
data = nfs_commitdata_alloc(true); data = nfs_commitdata_alloc();
if (!data) {
nfs_retry_commit(mds_pages, NULL, cinfo, -1);
return -ENOMEM;
}
data->ds_commit_index = -1; data->ds_commit_index = -1;
list_splice_init(mds_pages, &data->pages); list_splice_init(mds_pages, &data->pages);
list_add_tail(&data->list, &list); list_add_tail(&data->list, &list);
......
...@@ -92,6 +92,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -92,6 +92,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
info->maxfilesize = 0x7FFFFFFF; info->maxfilesize = 0x7FFFFFFF;
info->lease_time = 0; info->lease_time = 0;
info->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED; info->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
info->xattr_support = 0;
return 0; return 0;
} }
......
...@@ -123,7 +123,7 @@ static void nfs_readpage_release(struct nfs_page *req, int error) ...@@ -123,7 +123,7 @@ static void nfs_readpage_release(struct nfs_page *req, int error)
struct address_space *mapping = page_file_mapping(page); struct address_space *mapping = page_file_mapping(page);
if (PageUptodate(page)) if (PageUptodate(page))
nfs_readpage_to_fscache(inode, page); nfs_fscache_write_page(inode, page);
else if (!PageError(page) && !PagePrivate(page)) else if (!PageError(page) && !PagePrivate(page))
generic_error_remove_page(mapping, page); generic_error_remove_page(mapping, page);
unlock_page(page); unlock_page(page);
...@@ -194,10 +194,6 @@ static void nfs_initiate_read(struct nfs_pgio_header *hdr, ...@@ -194,10 +194,6 @@ static void nfs_initiate_read(struct nfs_pgio_header *hdr,
const struct nfs_rpc_ops *rpc_ops, const struct nfs_rpc_ops *rpc_ops,
struct rpc_task_setup *task_setup_data, int how) struct rpc_task_setup *task_setup_data, int how)
{ {
struct inode *inode = hdr->inode;
int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
task_setup_data->flags |= swap_flags;
rpc_ops->read_setup(hdr, msg); rpc_ops->read_setup(hdr, msg);
trace_nfs_initiate_read(hdr); trace_nfs_initiate_read(hdr);
} }
...@@ -290,9 +286,8 @@ static void nfs_readpage_result(struct rpc_task *task, ...@@ -290,9 +286,8 @@ static void nfs_readpage_result(struct rpc_task *task,
} }
static int static int
readpage_async_filler(void *data, struct page *page) readpage_async_filler(struct nfs_readdesc *desc, struct page *page)
{ {
struct nfs_readdesc *desc = data;
struct inode *inode = page_file_mapping(page)->host; struct inode *inode = page_file_mapping(page)->host;
unsigned int rsize = NFS_SERVER(inode)->rsize; unsigned int rsize = NFS_SERVER(inode)->rsize;
struct nfs_page *new; struct nfs_page *new;
...@@ -306,7 +301,7 @@ readpage_async_filler(void *data, struct page *page) ...@@ -306,7 +301,7 @@ readpage_async_filler(void *data, struct page *page)
aligned_len = min_t(unsigned int, ALIGN(len, rsize), PAGE_SIZE); aligned_len = min_t(unsigned int, ALIGN(len, rsize), PAGE_SIZE);
if (!IS_SYNC(page->mapping->host)) { if (!IS_SYNC(page->mapping->host)) {
error = nfs_readpage_from_fscache(page->mapping->host, page); error = nfs_fscache_read_page(page->mapping->host, page);
if (error == 0) if (error == 0)
goto out_unlock; goto out_unlock;
} }
...@@ -397,14 +392,16 @@ int nfs_readpage(struct file *file, struct page *page) ...@@ -397,14 +392,16 @@ int nfs_readpage(struct file *file, struct page *page)
return ret; return ret;
} }
int nfs_readpages(struct file *file, struct address_space *mapping, void nfs_readahead(struct readahead_control *ractl)
struct list_head *pages, unsigned nr_pages)
{ {
unsigned int nr_pages = readahead_count(ractl);
struct file *file = ractl->file;
struct nfs_readdesc desc; struct nfs_readdesc desc;
struct inode *inode = mapping->host; struct inode *inode = ractl->mapping->host;
struct page *page;
int ret; int ret;
trace_nfs_aop_readahead(inode, lru_to_page(pages), nr_pages); trace_nfs_aop_readahead(inode, readahead_pos(ractl), nr_pages);
nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); nfs_inc_stats(inode, NFSIOS_VFSREADPAGES);
ret = -ESTALE; ret = -ESTALE;
...@@ -422,14 +419,18 @@ int nfs_readpages(struct file *file, struct address_space *mapping, ...@@ -422,14 +419,18 @@ int nfs_readpages(struct file *file, struct address_space *mapping,
nfs_pageio_init_read(&desc.pgio, inode, false, nfs_pageio_init_read(&desc.pgio, inode, false,
&nfs_async_read_completion_ops); &nfs_async_read_completion_ops);
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); while ((page = readahead_page(ractl)) != NULL) {
ret = readpage_async_filler(&desc, page);
put_page(page);
if (ret)
break;
}
nfs_pageio_complete_read(&desc.pgio); nfs_pageio_complete_read(&desc.pgio);
put_nfs_open_context(desc.ctx); put_nfs_open_context(desc.ctx);
out: out:
trace_nfs_aop_readahead_done(inode, nr_pages, ret); trace_nfs_aop_readahead_done(inode, nr_pages, ret);
return ret;
} }
int __init nfs_init_readpagecache(void) int __init nfs_init_readpagecache(void)
......
...@@ -70,27 +70,17 @@ static mempool_t *nfs_wdata_mempool; ...@@ -70,27 +70,17 @@ static mempool_t *nfs_wdata_mempool;
static struct kmem_cache *nfs_cdata_cachep; static struct kmem_cache *nfs_cdata_cachep;
static mempool_t *nfs_commit_mempool; static mempool_t *nfs_commit_mempool;
struct nfs_commit_data *nfs_commitdata_alloc(bool never_fail) struct nfs_commit_data *nfs_commitdata_alloc(void)
{ {
struct nfs_commit_data *p; struct nfs_commit_data *p;
if (never_fail) p = kmem_cache_zalloc(nfs_cdata_cachep, nfs_io_gfp_mask());
p = mempool_alloc(nfs_commit_mempool, GFP_NOIO); if (!p) {
else {
/* It is OK to do some reclaim, not no safe to wait
* for anything to be returned to the pool.
* mempool_alloc() cannot handle that particular combination,
* so we need two separate attempts.
*/
p = mempool_alloc(nfs_commit_mempool, GFP_NOWAIT); p = mempool_alloc(nfs_commit_mempool, GFP_NOWAIT);
if (!p)
p = kmem_cache_alloc(nfs_cdata_cachep, GFP_NOIO |
__GFP_NOWARN | __GFP_NORETRY);
if (!p) if (!p)
return NULL; return NULL;
}
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
}
INIT_LIST_HEAD(&p->pages); INIT_LIST_HEAD(&p->pages);
return p; return p;
} }
...@@ -104,9 +94,15 @@ EXPORT_SYMBOL_GPL(nfs_commit_free); ...@@ -104,9 +94,15 @@ EXPORT_SYMBOL_GPL(nfs_commit_free);
static struct nfs_pgio_header *nfs_writehdr_alloc(void) static struct nfs_pgio_header *nfs_writehdr_alloc(void)
{ {
struct nfs_pgio_header *p = mempool_alloc(nfs_wdata_mempool, GFP_KERNEL); struct nfs_pgio_header *p;
p = kmem_cache_zalloc(nfs_wdata_cachep, nfs_io_gfp_mask());
if (!p) {
p = mempool_alloc(nfs_wdata_mempool, GFP_NOWAIT);
if (!p)
return NULL;
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
}
p->rw_mode = FMODE_WRITE; p->rw_mode = FMODE_WRITE;
return p; return p;
} }
...@@ -306,7 +302,7 @@ static void nfs_set_pageerror(struct address_space *mapping) ...@@ -306,7 +302,7 @@ static void nfs_set_pageerror(struct address_space *mapping)
/* Force file size revalidation */ /* Force file size revalidation */
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfs_set_cache_invalid(inode, NFS_INO_REVAL_FORCED | nfs_set_cache_invalid(inode, NFS_INO_REVAL_FORCED |
NFS_INO_REVAL_PAGECACHE | NFS_INO_INVALID_CHANGE |
NFS_INO_INVALID_SIZE); NFS_INO_INVALID_SIZE);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
...@@ -316,7 +312,10 @@ static void nfs_mapping_set_error(struct page *page, int error) ...@@ -316,7 +312,10 @@ static void nfs_mapping_set_error(struct page *page, int error)
struct address_space *mapping = page_file_mapping(page); struct address_space *mapping = page_file_mapping(page);
SetPageError(page); SetPageError(page);
mapping_set_error(mapping, error); filemap_set_wb_err(mapping, error);
if (mapping->host)
errseq_set(&mapping->host->i_sb->s_wb_err,
error == -ENOSPC ? -ENOSPC : -EIO);
nfs_set_pageerror(mapping); nfs_set_pageerror(mapping);
} }
...@@ -1417,6 +1416,8 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr, ...@@ -1417,6 +1416,8 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr,
{ {
int priority = flush_task_priority(how); int priority = flush_task_priority(how);
if (IS_SWAPFILE(hdr->inode))
task_setup_data->flags |= RPC_TASK_SWAPPER;
task_setup_data->priority = priority; task_setup_data->priority = priority;
rpc_ops->write_setup(hdr, msg, &task_setup_data->rpc_client); rpc_ops->write_setup(hdr, msg, &task_setup_data->rpc_client);
trace_nfs_initiate_write(hdr); trace_nfs_initiate_write(hdr);
...@@ -1829,7 +1830,11 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, ...@@ -1829,7 +1830,11 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
if (list_empty(head)) if (list_empty(head))
return 0; return 0;
data = nfs_commitdata_alloc(true); data = nfs_commitdata_alloc();
if (!data) {
nfs_retry_commit(head, NULL, cinfo, -1);
return -ENOMEM;
}
/* Set up the argument struct */ /* Set up the argument struct */
nfs_init_commit(data, head, NULL, cinfo); nfs_init_commit(data, head, NULL, cinfo);
......
...@@ -45,11 +45,6 @@ ...@@ -45,11 +45,6 @@
*/ */
#define NFS_MAX_TRANSPORTS 16 #define NFS_MAX_TRANSPORTS 16
/*
* These are the default flags for swap requests
*/
#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
/* /*
* Size of the NFS directory verifier * Size of the NFS directory verifier
*/ */
...@@ -101,13 +96,17 @@ struct nfs_open_context { ...@@ -101,13 +96,17 @@ struct nfs_open_context {
struct nfs_open_dir_context { struct nfs_open_dir_context {
struct list_head list; struct list_head list;
atomic_t cache_hits;
atomic_t cache_misses;
unsigned long attr_gencount; unsigned long attr_gencount;
__be32 verf[NFS_DIR_VERIFIER_SIZE]; __be32 verf[NFS_DIR_VERIFIER_SIZE];
__u64 dir_cookie; __u64 dir_cookie;
__u64 dup_cookie; __u64 last_cookie;
pgoff_t page_index; pgoff_t page_index;
signed char duped; unsigned int dtsize;
bool force_clear;
bool eof; bool eof;
struct rcu_head rcu_head;
}; };
/* /*
...@@ -247,7 +246,6 @@ struct nfs4_copy_state { ...@@ -247,7 +246,6 @@ struct nfs4_copy_state {
#define NFS_INO_INVALID_ATIME BIT(2) /* cached atime is invalid */ #define NFS_INO_INVALID_ATIME BIT(2) /* cached atime is invalid */
#define NFS_INO_INVALID_ACCESS BIT(3) /* cached access cred invalid */ #define NFS_INO_INVALID_ACCESS BIT(3) /* cached access cred invalid */
#define NFS_INO_INVALID_ACL BIT(4) /* cached acls are invalid */ #define NFS_INO_INVALID_ACL BIT(4) /* cached acls are invalid */
#define NFS_INO_REVAL_PAGECACHE BIT(5) /* must revalidate pagecache */
#define NFS_INO_REVAL_FORCED BIT(6) /* force revalidation ignoring a delegation */ #define NFS_INO_REVAL_FORCED BIT(6) /* force revalidation ignoring a delegation */
#define NFS_INO_INVALID_LABEL BIT(7) /* cached label is invalid */ #define NFS_INO_INVALID_LABEL BIT(7) /* cached label is invalid */
#define NFS_INO_INVALID_CHANGE BIT(8) /* cached change is invalid */ #define NFS_INO_INVALID_CHANGE BIT(8) /* cached change is invalid */
...@@ -273,12 +271,11 @@ struct nfs4_copy_state { ...@@ -273,12 +271,11 @@ struct nfs4_copy_state {
/* /*
* Bit offsets in flags field * Bit offsets in flags field
*/ */
#define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */
#define NFS_INO_STALE (1) /* possible stale inode */ #define NFS_INO_STALE (1) /* possible stale inode */
#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
#define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ #define NFS_INO_INVALIDATING (3) /* inode is being invalidated */
#define NFS_INO_PRESERVE_UNLINKED (4) /* preserve file if removed while open */
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
#define NFS_INO_FORCE_READDIR (7) /* force readdirplus */
#define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
...@@ -355,17 +352,15 @@ static inline void nfs_mark_for_revalidate(struct inode *inode) ...@@ -355,17 +352,15 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE nfsi->cache_validity |= NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
| NFS_INO_INVALID_ACCESS NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
| NFS_INO_INVALID_ACL NFS_INO_INVALID_SIZE;
| NFS_INO_INVALID_CHANGE
| NFS_INO_INVALID_CTIME;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfsi->cache_validity |= NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
static inline int nfs_server_capable(struct inode *inode, int cap) static inline int nfs_server_capable(const struct inode *inode, int cap)
{ {
return NFS_SERVER(inode)->caps & cap; return NFS_SERVER(inode)->caps & cap;
} }
...@@ -513,10 +508,10 @@ static inline const struct cred *nfs_file_cred(struct file *file) ...@@ -513,10 +508,10 @@ static inline const struct cred *nfs_file_cred(struct file *file)
* linux/fs/nfs/direct.c * linux/fs/nfs/direct.c
*/ */
extern ssize_t nfs_direct_IO(struct kiocb *, struct iov_iter *); extern ssize_t nfs_direct_IO(struct kiocb *, struct iov_iter *);
extern ssize_t nfs_file_direct_read(struct kiocb *iocb, ssize_t nfs_file_direct_read(struct kiocb *iocb,
struct iov_iter *iter); struct iov_iter *iter, bool swap);
extern ssize_t nfs_file_direct_write(struct kiocb *iocb, ssize_t nfs_file_direct_write(struct kiocb *iocb,
struct iov_iter *iter); struct iov_iter *iter, bool swap);
/* /*
* linux/fs/nfs/dir.c * linux/fs/nfs/dir.c
...@@ -585,24 +580,22 @@ extern int nfs_wb_all(struct inode *inode); ...@@ -585,24 +580,22 @@ extern int nfs_wb_all(struct inode *inode);
extern int nfs_wb_page(struct inode *inode, struct page *page); extern int nfs_wb_page(struct inode *inode, struct page *page);
int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio); int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio);
extern int nfs_commit_inode(struct inode *, int); extern int nfs_commit_inode(struct inode *, int);
extern struct nfs_commit_data *nfs_commitdata_alloc(bool never_fail); extern struct nfs_commit_data *nfs_commitdata_alloc(void);
extern void nfs_commit_free(struct nfs_commit_data *data); extern void nfs_commit_free(struct nfs_commit_data *data);
bool nfs_commit_end(struct nfs_mds_commit_info *cinfo); bool nfs_commit_end(struct nfs_mds_commit_info *cinfo);
static inline int static inline bool nfs_have_writebacks(const struct inode *inode)
nfs_have_writebacks(struct inode *inode)
{ {
if (S_ISREG(inode->i_mode)) if (S_ISREG(inode->i_mode))
return atomic_long_read(&NFS_I(inode)->nrequests) != 0; return atomic_long_read(&NFS_I(inode)->nrequests) != 0;
return 0; return false;
} }
/* /*
* linux/fs/nfs/read.c * linux/fs/nfs/read.c
*/ */
extern int nfs_readpage(struct file *, struct page *); extern int nfs_readpage(struct file *, struct page *);
extern int nfs_readpages(struct file *, struct address_space *, void nfs_readahead(struct readahead_control *);
struct list_head *, unsigned);
/* /*
* inline functions * inline functions
......
...@@ -152,6 +152,7 @@ struct nfs_server { ...@@ -152,6 +152,7 @@ struct nfs_server {
#define NFS_MOUNT_SOFTREVAL 0x800000 #define NFS_MOUNT_SOFTREVAL 0x800000
#define NFS_MOUNT_WRITE_EAGER 0x01000000 #define NFS_MOUNT_WRITE_EAGER 0x01000000
#define NFS_MOUNT_WRITE_WAIT 0x02000000 #define NFS_MOUNT_WRITE_WAIT 0x02000000
#define NFS_MOUNT_TRUNK_DISCOVERY 0x04000000
unsigned int fattr_valid; /* Valid attributes */ unsigned int fattr_valid; /* Valid attributes */
unsigned int caps; /* server capabilities */ unsigned int caps; /* server capabilities */
......
...@@ -745,8 +745,7 @@ struct nfs_auth_info { ...@@ -745,8 +745,7 @@ struct nfs_auth_info {
*/ */
struct nfs_entry { struct nfs_entry {
__u64 ino; __u64 ino;
__u64 cookie, __u64 cookie;
prev_cookie;
const char * name; const char * name;
unsigned int len; unsigned int len;
int eof; int eof;
...@@ -1798,6 +1797,8 @@ struct nfs_rpc_ops { ...@@ -1798,6 +1797,8 @@ struct nfs_rpc_ops {
struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *, struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *, rpc_authflavor_t); struct nfs_fattr *, rpc_authflavor_t);
int (*discover_trunking)(struct nfs_server *, struct nfs_fh *); int (*discover_trunking)(struct nfs_server *, struct nfs_fh *);
void (*enable_swap)(struct inode *inode);
void (*disable_swap)(struct inode *inode);
}; };
/* /*
......
...@@ -99,6 +99,7 @@ struct rpc_auth_create_args { ...@@ -99,6 +99,7 @@ struct rpc_auth_create_args {
/* Flags for rpcauth_lookupcred() */ /* Flags for rpcauth_lookupcred() */
#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
#define RPCAUTH_LOOKUP_ASYNC 0x02 /* Don't block waiting for memory */
/* /*
* Client authentication ops * Client authentication ops
......
...@@ -124,7 +124,6 @@ struct rpc_task_setup { ...@@ -124,7 +124,6 @@ struct rpc_task_setup {
#define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */ #define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */
#define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */ #define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */
#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */
#define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */
#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
#define RPC_TASK_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */ #define RPC_TASK_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
...@@ -263,6 +262,7 @@ void rpc_destroy_mempool(void); ...@@ -263,6 +262,7 @@ void rpc_destroy_mempool(void);
extern struct workqueue_struct *rpciod_workqueue; extern struct workqueue_struct *rpciod_workqueue;
extern struct workqueue_struct *xprtiod_workqueue; extern struct workqueue_struct *xprtiod_workqueue;
void rpc_prepare_task(struct rpc_task *task); void rpc_prepare_task(struct rpc_task *task);
gfp_t rpc_task_gfp_mask(void);
static inline int rpc_wait_for_completion_task(struct rpc_task *task) static inline int rpc_wait_for_completion_task(struct rpc_task *task)
{ {
......
...@@ -139,6 +139,9 @@ struct rpc_xprt_ops { ...@@ -139,6 +139,9 @@ struct rpc_xprt_ops {
void (*rpcbind)(struct rpc_task *task); void (*rpcbind)(struct rpc_task *task);
void (*set_port)(struct rpc_xprt *xprt, unsigned short port); void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task); void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task);
int (*get_srcaddr)(struct rpc_xprt *xprt, char *buf,
size_t buflen);
unsigned short (*get_srcport)(struct rpc_xprt *xprt);
int (*buf_alloc)(struct rpc_task *task); int (*buf_alloc)(struct rpc_task *task);
void (*buf_free)(struct rpc_task *task); void (*buf_free)(struct rpc_task *task);
void (*prepare_request)(struct rpc_rqst *req); void (*prepare_request)(struct rpc_rqst *req);
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
int init_socket_xprt(void); int init_socket_xprt(void);
void cleanup_socket_xprt(void); void cleanup_socket_xprt(void);
unsigned short get_srcport(struct rpc_xprt *);
#define RPC_MIN_RESVPORT (1U) #define RPC_MIN_RESVPORT (1U)
#define RPC_MAX_RESVPORT (65535U) #define RPC_MAX_RESVPORT (65535U)
...@@ -89,5 +88,7 @@ struct sock_xprt { ...@@ -89,5 +88,7 @@ struct sock_xprt {
#define XPRT_SOCK_WAKE_WRITE (5) #define XPRT_SOCK_WAKE_WRITE (5)
#define XPRT_SOCK_WAKE_PENDING (6) #define XPRT_SOCK_WAKE_PENDING (6)
#define XPRT_SOCK_WAKE_DISCONNECT (7) #define XPRT_SOCK_WAKE_DISCONNECT (7)
#define XPRT_SOCK_CONNECT_SENT (8)
#define XPRT_SOCK_NOSPACE (9)
#endif /* _LINUX_SUNRPC_XPRTSOCK_H */ #endif /* _LINUX_SUNRPC_XPRTSOCK_H */
...@@ -311,7 +311,6 @@ TRACE_EVENT(rpc_request, ...@@ -311,7 +311,6 @@ TRACE_EVENT(rpc_request,
{ RPC_TASK_MOVEABLE, "MOVEABLE" }, \ { RPC_TASK_MOVEABLE, "MOVEABLE" }, \
{ RPC_TASK_NULLCREDS, "NULLCREDS" }, \ { RPC_TASK_NULLCREDS, "NULLCREDS" }, \
{ RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \ { RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \
{ RPC_TASK_ROOTCREDS, "ROOTCREDS" }, \
{ RPC_TASK_DYNAMIC, "DYNAMIC" }, \ { RPC_TASK_DYNAMIC, "DYNAMIC" }, \
{ RPC_TASK_NO_ROUND_ROBIN, "NO_ROUND_ROBIN" }, \ { RPC_TASK_NO_ROUND_ROBIN, "NO_ROUND_ROBIN" }, \
{ RPC_TASK_SOFT, "SOFT" }, \ { RPC_TASK_SOFT, "SOFT" }, \
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#define NFS4_OPEN_RESULT_CONFIRM 0x0002 #define NFS4_OPEN_RESULT_CONFIRM 0x0002
#define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004 #define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004
#define NFS4_OPEN_RESULT_PRESERVE_UNLINKED 0x0008
#define NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK 0x0020 #define NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK 0x0020
#define NFS4_SHARE_ACCESS_MASK 0x000F #define NFS4_SHARE_ACCESS_MASK 0x000F
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#define NFSDBG_CALLBACK 0x0100 #define NFSDBG_CALLBACK 0x0100
#define NFSDBG_CLIENT 0x0200 #define NFSDBG_CLIENT 0x0200
#define NFSDBG_MOUNT 0x0400 #define NFSDBG_MOUNT 0x0400
#define NFSDBG_FSCACHE 0x0800 #define NFSDBG_FSCACHE 0x0800 /* unused */
#define NFSDBG_PNFS 0x1000 #define NFSDBG_PNFS 0x1000
#define NFSDBG_PNFS_LD 0x2000 #define NFSDBG_PNFS_LD 0x2000
#define NFSDBG_STATE 0x4000 #define NFSDBG_STATE 0x4000
......
...@@ -615,6 +615,8 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) ...@@ -615,6 +615,8 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
}; };
struct rpc_cred *ret; struct rpc_cred *ret;
if (RPC_IS_ASYNC(task))
lookupflags |= RPCAUTH_LOOKUP_ASYNC;
ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
put_cred(acred.cred); put_cred(acred.cred);
return ret; return ret;
...@@ -631,6 +633,8 @@ rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags) ...@@ -631,6 +633,8 @@ rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags)
if (!acred.principal) if (!acred.principal)
return NULL; return NULL;
if (RPC_IS_ASYNC(task))
lookupflags |= RPCAUTH_LOOKUP_ASYNC;
return auth->au_ops->lookup_cred(auth, &acred, lookupflags); return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
} }
...@@ -654,7 +658,7 @@ rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags) ...@@ -654,7 +658,7 @@ rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags)
}; };
if (flags & RPC_TASK_ASYNC) if (flags & RPC_TASK_ASYNC)
lookupflags |= RPCAUTH_LOOKUP_NEW; lookupflags |= RPCAUTH_LOOKUP_NEW | RPCAUTH_LOOKUP_ASYNC;
if (task->tk_op_cred) if (task->tk_op_cred)
/* Task must use exactly this rpc_cred */ /* Task must use exactly this rpc_cred */
new = get_rpccred(task->tk_op_cred); new = get_rpccred(task->tk_op_cred);
...@@ -666,7 +670,7 @@ rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags) ...@@ -666,7 +670,7 @@ rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags)
/* If machine cred couldn't be bound, try a root cred */ /* If machine cred couldn't be bound, try a root cred */
if (new) if (new)
; ;
else if (cred == &machine_cred || (flags & RPC_TASK_ROOTCREDS)) else if (cred == &machine_cred)
new = rpcauth_bind_root_cred(task, lookupflags); new = rpcauth_bind_root_cred(task, lookupflags);
else if (flags & RPC_TASK_NULLCREDS) else if (flags & RPC_TASK_NULLCREDS)
new = authnull_ops.lookup_cred(NULL, NULL, 0); new = authnull_ops.lookup_cred(NULL, NULL, 0);
......
...@@ -146,7 +146,7 @@ gss_alloc_context(void) ...@@ -146,7 +146,7 @@ gss_alloc_context(void)
{ {
struct gss_cl_ctx *ctx; struct gss_cl_ctx *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_NOFS); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) { if (ctx != NULL) {
ctx->gc_proc = RPC_GSS_PROC_DATA; ctx->gc_proc = RPC_GSS_PROC_DATA;
ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */ ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */
...@@ -209,7 +209,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct ...@@ -209,7 +209,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
p = ERR_PTR(-EFAULT); p = ERR_PTR(-EFAULT);
goto err; goto err;
} }
ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_NOFS); ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
trace_rpcgss_import_ctx(ret); trace_rpcgss_import_ctx(ret);
p = ERR_PTR(ret); p = ERR_PTR(ret);
...@@ -511,7 +511,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, ...@@ -511,7 +511,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
int vers; int vers;
int err = -ENOMEM; int err = -ENOMEM;
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL);
if (gss_msg == NULL) if (gss_msg == NULL)
goto err; goto err;
vers = get_pipe_version(gss_auth->net); vers = get_pipe_version(gss_auth->net);
...@@ -527,7 +527,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, ...@@ -527,7 +527,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
gss_msg->auth = gss_auth; gss_msg->auth = gss_auth;
kref_get(&gss_auth->kref); kref_get(&gss_auth->kref);
if (service_name) { if (service_name) {
gss_msg->service_name = kstrdup_const(service_name, GFP_NOFS); gss_msg->service_name = kstrdup_const(service_name, GFP_KERNEL);
if (!gss_msg->service_name) { if (!gss_msg->service_name) {
err = -ENOMEM; err = -ENOMEM;
goto err_put_pipe_version; goto err_put_pipe_version;
...@@ -703,7 +703,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) ...@@ -703,7 +703,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (mlen > MSG_BUF_MAXSIZE) if (mlen > MSG_BUF_MAXSIZE)
goto out; goto out;
err = -ENOMEM; err = -ENOMEM;
buf = kmalloc(mlen, GFP_NOFS); buf = kmalloc(mlen, GFP_KERNEL);
if (!buf) if (!buf)
goto out; goto out;
...@@ -1220,7 +1220,7 @@ gss_dup_cred(struct gss_auth *gss_auth, struct gss_cred *gss_cred) ...@@ -1220,7 +1220,7 @@ gss_dup_cred(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
struct gss_cred *new; struct gss_cred *new;
/* Make a copy of the cred so that we can reference count it */ /* Make a copy of the cred so that we can reference count it */
new = kzalloc(sizeof(*gss_cred), GFP_NOFS); new = kzalloc(sizeof(*gss_cred), GFP_KERNEL);
if (new) { if (new) {
struct auth_cred acred = { struct auth_cred acred = {
.cred = gss_cred->gc_base.cr_cred, .cred = gss_cred->gc_base.cr_cred,
...@@ -1343,7 +1343,11 @@ gss_hash_cred(struct auth_cred *acred, unsigned int hashbits) ...@@ -1343,7 +1343,11 @@ gss_hash_cred(struct auth_cred *acred, unsigned int hashbits)
static struct rpc_cred * static struct rpc_cred *
gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
{ {
return rpcauth_lookup_credcache(auth, acred, flags, GFP_NOFS); gfp_t gfp = GFP_KERNEL;
if (flags & RPCAUTH_LOOKUP_ASYNC)
gfp = GFP_NOWAIT | __GFP_NOWARN;
return rpcauth_lookup_credcache(auth, acred, flags, gfp);
} }
static struct rpc_cred * static struct rpc_cred *
...@@ -1669,7 +1673,7 @@ gss_validate(struct rpc_task *task, struct xdr_stream *xdr) ...@@ -1669,7 +1673,7 @@ gss_validate(struct rpc_task *task, struct xdr_stream *xdr)
if (!p) if (!p)
goto validate_failed; goto validate_failed;
seq = kmalloc(4, GFP_NOFS); seq = kmalloc(4, GFP_KERNEL);
if (!seq) if (!seq)
goto validate_failed; goto validate_failed;
*seq = cpu_to_be32(task->tk_rqstp->rq_seqno); *seq = cpu_to_be32(task->tk_rqstp->rq_seqno);
...@@ -1779,11 +1783,11 @@ alloc_enc_pages(struct rpc_rqst *rqstp) ...@@ -1779,11 +1783,11 @@ alloc_enc_pages(struct rpc_rqst *rqstp)
rqstp->rq_enc_pages rqstp->rq_enc_pages
= kmalloc_array(rqstp->rq_enc_pages_num, = kmalloc_array(rqstp->rq_enc_pages_num,
sizeof(struct page *), sizeof(struct page *),
GFP_NOFS); GFP_KERNEL);
if (!rqstp->rq_enc_pages) if (!rqstp->rq_enc_pages)
goto out; goto out;
for (i=0; i < rqstp->rq_enc_pages_num; i++) { for (i=0; i < rqstp->rq_enc_pages_num; i++) {
rqstp->rq_enc_pages[i] = alloc_page(GFP_NOFS); rqstp->rq_enc_pages[i] = alloc_page(GFP_KERNEL);
if (rqstp->rq_enc_pages[i] == NULL) if (rqstp->rq_enc_pages[i] == NULL)
goto out_free; goto out_free;
} }
...@@ -1987,7 +1991,7 @@ gss_unwrap_resp_integ(struct rpc_task *task, struct rpc_cred *cred, ...@@ -1987,7 +1991,7 @@ gss_unwrap_resp_integ(struct rpc_task *task, struct rpc_cred *cred,
if (offset + len > rcv_buf->len) if (offset + len > rcv_buf->len)
goto unwrap_failed; goto unwrap_failed;
mic.len = len; mic.len = len;
mic.data = kmalloc(len, GFP_NOFS); mic.data = kmalloc(len, GFP_KERNEL);
if (!mic.data) if (!mic.data)
goto unwrap_failed; goto unwrap_failed;
if (read_bytes_from_xdr_buf(rcv_buf, offset, mic.data, mic.len)) if (read_bytes_from_xdr_buf(rcv_buf, offset, mic.data, mic.len))
......
...@@ -35,7 +35,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest) ...@@ -35,7 +35,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
if (unlikely(q > end || q < p)) if (unlikely(q > end || q < p))
return ERR_PTR(-EFAULT); return ERR_PTR(-EFAULT);
if (len) { if (len) {
dest->data = kmemdup(p, len, GFP_NOFS); dest->data = kmemdup(p, len, GFP_KERNEL);
if (unlikely(dest->data == NULL)) if (unlikely(dest->data == NULL))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} else } else
......
...@@ -161,7 +161,7 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, ...@@ -161,7 +161,7 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
return GSS_S_FAILURE; return GSS_S_FAILURE;
} }
checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS); checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_KERNEL);
if (checksumdata == NULL) if (checksumdata == NULL)
return GSS_S_FAILURE; return GSS_S_FAILURE;
...@@ -169,7 +169,7 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, ...@@ -169,7 +169,7 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
if (IS_ERR(tfm)) if (IS_ERR(tfm))
goto out_free_cksum; goto out_free_cksum;
req = ahash_request_alloc(tfm, GFP_NOFS); req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req) if (!req)
goto out_free_ahash; goto out_free_ahash;
...@@ -257,7 +257,7 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen, ...@@ -257,7 +257,7 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
return GSS_S_FAILURE; return GSS_S_FAILURE;
} }
checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS); checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_KERNEL);
if (!checksumdata) if (!checksumdata)
return GSS_S_FAILURE; return GSS_S_FAILURE;
...@@ -265,7 +265,7 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen, ...@@ -265,7 +265,7 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
if (IS_ERR(tfm)) if (IS_ERR(tfm))
goto out_free_cksum; goto out_free_cksum;
req = ahash_request_alloc(tfm, GFP_NOFS); req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req) if (!req)
goto out_free_ahash; goto out_free_ahash;
...@@ -554,7 +554,7 @@ gss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf, ...@@ -554,7 +554,7 @@ gss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf,
WARN_ON(0); WARN_ON(0);
return -ENOMEM; return -ENOMEM;
} }
data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_NOFS); data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
......
...@@ -49,7 +49,7 @@ krb5_make_seq_num(struct krb5_ctx *kctx, ...@@ -49,7 +49,7 @@ krb5_make_seq_num(struct krb5_ctx *kctx,
unsigned char *plain; unsigned char *plain;
s32 code; s32 code;
plain = kmalloc(8, GFP_NOFS); plain = kmalloc(8, GFP_KERNEL);
if (!plain) if (!plain)
return -ENOMEM; return -ENOMEM;
...@@ -80,7 +80,7 @@ krb5_get_seq_num(struct krb5_ctx *kctx, ...@@ -80,7 +80,7 @@ krb5_get_seq_num(struct krb5_ctx *kctx,
dprintk("RPC: krb5_get_seq_num:\n"); dprintk("RPC: krb5_get_seq_num:\n");
plain = kmalloc(8, GFP_NOFS); plain = kmalloc(8, GFP_KERNEL);
if (!plain) if (!plain)
return -ENOMEM; return -ENOMEM;
......
...@@ -409,7 +409,7 @@ static u32 ...@@ -409,7 +409,7 @@ static u32
gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
struct xdr_buf *buf, struct page **pages) struct xdr_buf *buf, struct page **pages)
{ {
u8 *ptr, *plainhdr; u8 *ptr;
time64_t now; time64_t now;
u8 flags = 0x00; u8 flags = 0x00;
__be16 *be16ptr; __be16 *be16ptr;
...@@ -426,7 +426,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, ...@@ -426,7 +426,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
return GSS_S_FAILURE; return GSS_S_FAILURE;
/* construct gss token header */ /* construct gss token header */
ptr = plainhdr = buf->head[0].iov_base + offset; ptr = buf->head[0].iov_base + offset;
*ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff); *ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
*ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff); *ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);
......
...@@ -40,11 +40,19 @@ unx_destroy(struct rpc_auth *auth) ...@@ -40,11 +40,19 @@ unx_destroy(struct rpc_auth *auth)
/* /*
* Lookup AUTH_UNIX creds for current process * Lookup AUTH_UNIX creds for current process
*/ */
static struct rpc_cred * static struct rpc_cred *unx_lookup_cred(struct rpc_auth *auth,
unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) struct auth_cred *acred, int flags)
{ {
struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS); struct rpc_cred *ret;
ret = kmalloc(sizeof(*ret), rpc_task_gfp_mask());
if (!ret) {
if (!(flags & RPCAUTH_LOOKUP_ASYNC))
return ERR_PTR(-ENOMEM);
ret = mempool_alloc(unix_pool, GFP_NOWAIT);
if (!ret)
return ERR_PTR(-ENOMEM);
}
rpcauth_init_cred(ret, acred, auth, &unix_credops); rpcauth_init_cred(ret, acred, auth, &unix_credops);
ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
return ret; return ret;
......
...@@ -75,9 +75,9 @@ static int xprt_alloc_xdr_buf(struct xdr_buf *buf, gfp_t gfp_flags) ...@@ -75,9 +75,9 @@ static int xprt_alloc_xdr_buf(struct xdr_buf *buf, gfp_t gfp_flags)
return 0; return 0;
} }
static static struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt)
struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt, gfp_t gfp_flags)
{ {
gfp_t gfp_flags = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
struct rpc_rqst *req; struct rpc_rqst *req;
/* Pre-allocate one backchannel rpc_rqst */ /* Pre-allocate one backchannel rpc_rqst */
...@@ -154,7 +154,7 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs) ...@@ -154,7 +154,7 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
INIT_LIST_HEAD(&tmp_list); INIT_LIST_HEAD(&tmp_list);
for (i = 0; i < min_reqs; i++) { for (i = 0; i < min_reqs; i++) {
/* Pre-allocate one backchannel rpc_rqst */ /* Pre-allocate one backchannel rpc_rqst */
req = xprt_alloc_bc_req(xprt, GFP_KERNEL); req = xprt_alloc_bc_req(xprt);
if (req == NULL) { if (req == NULL) {
printk(KERN_ERR "Failed to create bc rpc_rqst\n"); printk(KERN_ERR "Failed to create bc rpc_rqst\n");
goto out_free; goto out_free;
...@@ -343,7 +343,7 @@ struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid) ...@@ -343,7 +343,7 @@ struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid)
break; break;
} else if (req) } else if (req)
break; break;
new = xprt_alloc_bc_req(xprt, GFP_KERNEL); new = xprt_alloc_bc_req(xprt);
} while (new); } while (new);
return req; return req;
} }
......
...@@ -1065,7 +1065,9 @@ rpc_task_get_next_xprt(struct rpc_clnt *clnt) ...@@ -1065,7 +1065,9 @@ rpc_task_get_next_xprt(struct rpc_clnt *clnt)
static static
void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt)
{ {
if (task->tk_xprt) if (task->tk_xprt &&
!(test_bit(XPRT_OFFLINE, &task->tk_xprt->state) &&
(task->tk_flags & RPC_TASK_MOVEABLE)))
return; return;
if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN) if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN)
task->tk_xprt = rpc_task_get_first_xprt(clnt); task->tk_xprt = rpc_task_get_first_xprt(clnt);
...@@ -1085,8 +1087,6 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) ...@@ -1085,8 +1087,6 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
task->tk_flags |= RPC_TASK_TIMEOUT; task->tk_flags |= RPC_TASK_TIMEOUT;
if (clnt->cl_noretranstimeo) if (clnt->cl_noretranstimeo)
task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
if (atomic_read(&clnt->cl_swapper))
task->tk_flags |= RPC_TASK_SWAPPER;
/* Add to the client's list of all tasks */ /* Add to the client's list of all tasks */
spin_lock(&clnt->cl_lock); spin_lock(&clnt->cl_lock);
list_add_tail(&task->tk_task, &clnt->cl_tasks); list_add_tail(&task->tk_task, &clnt->cl_tasks);
...@@ -1745,6 +1745,9 @@ call_refreshresult(struct rpc_task *task) ...@@ -1745,6 +1745,9 @@ call_refreshresult(struct rpc_task *task)
task->tk_cred_retry--; task->tk_cred_retry--;
trace_rpc_retry_refresh_status(task); trace_rpc_retry_refresh_status(task);
return; return;
case -ENOMEM:
rpc_delay(task, HZ >> 4);
return;
} }
trace_rpc_refresh_status(task); trace_rpc_refresh_status(task);
rpc_call_rpcerror(task, status); rpc_call_rpcerror(task, status);
...@@ -2793,7 +2796,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, ...@@ -2793,7 +2796,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
return -EINVAL; return -EINVAL;
} }
data = kmalloc(sizeof(*data), GFP_NOFS); data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
data->xps = xprt_switch_get(xps); data->xps = xprt_switch_get(xps);
...@@ -3068,6 +3071,8 @@ rpc_clnt_swap_activate_callback(struct rpc_clnt *clnt, ...@@ -3068,6 +3071,8 @@ rpc_clnt_swap_activate_callback(struct rpc_clnt *clnt,
int int
rpc_clnt_swap_activate(struct rpc_clnt *clnt) rpc_clnt_swap_activate(struct rpc_clnt *clnt)
{ {
while (clnt != clnt->cl_parent)
clnt = clnt->cl_parent;
if (atomic_inc_return(&clnt->cl_swapper) == 1) if (atomic_inc_return(&clnt->cl_swapper) == 1)
return rpc_clnt_iterate_for_each_xprt(clnt, return rpc_clnt_iterate_for_each_xprt(clnt,
rpc_clnt_swap_activate_callback, NULL); rpc_clnt_swap_activate_callback, NULL);
......
...@@ -714,7 +714,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -714,7 +714,7 @@ void rpcb_getport_async(struct rpc_task *task)
goto bailout_nofree; goto bailout_nofree;
} }
map = kzalloc(sizeof(struct rpcbind_args), GFP_NOFS); map = kzalloc(sizeof(struct rpcbind_args), rpc_task_gfp_mask());
if (!map) { if (!map) {
status = -ENOMEM; status = -ENOMEM;
goto bailout_release_client; goto bailout_release_client;
...@@ -730,7 +730,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -730,7 +730,7 @@ void rpcb_getport_async(struct rpc_task *task)
case RPCBVERS_4: case RPCBVERS_4:
case RPCBVERS_3: case RPCBVERS_3:
map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID]; map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];
map->r_addr = rpc_sockaddr2uaddr(sap, GFP_NOFS); map->r_addr = rpc_sockaddr2uaddr(sap, rpc_task_gfp_mask());
if (!map->r_addr) { if (!map->r_addr) {
status = -ENOMEM; status = -ENOMEM;
goto bailout_free_args; goto bailout_free_args;
......
...@@ -57,6 +57,13 @@ struct workqueue_struct *rpciod_workqueue __read_mostly; ...@@ -57,6 +57,13 @@ struct workqueue_struct *rpciod_workqueue __read_mostly;
struct workqueue_struct *xprtiod_workqueue __read_mostly; struct workqueue_struct *xprtiod_workqueue __read_mostly;
EXPORT_SYMBOL_GPL(xprtiod_workqueue); EXPORT_SYMBOL_GPL(xprtiod_workqueue);
gfp_t rpc_task_gfp_mask(void)
{
if (current->flags & PF_WQ_WORKER)
return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
return GFP_KERNEL;
}
unsigned long unsigned long
rpc_task_timeout(const struct rpc_task *task) rpc_task_timeout(const struct rpc_task *task)
{ {
...@@ -186,11 +193,6 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, ...@@ -186,11 +193,6 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue,
/* /*
* Add new request to wait queue. * Add new request to wait queue.
*
* Swapper tasks always get inserted at the head of the queue.
* This should avoid many nasty memory deadlocks and hopefully
* improve overall performance.
* Everyone else gets appended to the queue to ensure proper FIFO behavior.
*/ */
static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
struct rpc_task *task, struct rpc_task *task,
...@@ -199,8 +201,6 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, ...@@ -199,8 +201,6 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
INIT_LIST_HEAD(&task->u.tk_wait.timer_list); INIT_LIST_HEAD(&task->u.tk_wait.timer_list);
if (RPC_IS_PRIORITY(queue)) if (RPC_IS_PRIORITY(queue))
__rpc_add_wait_queue_priority(queue, task, queue_priority); __rpc_add_wait_queue_priority(queue, task, queue_priority);
else if (RPC_IS_SWAPPER(task))
list_add(&task->u.tk_wait.list, &queue->tasks[0]);
else else
list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
task->tk_waitqueue = queue; task->tk_waitqueue = queue;
...@@ -876,6 +876,15 @@ void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) ...@@ -876,6 +876,15 @@ void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
ops->rpc_release(calldata); ops->rpc_release(calldata);
} }
static bool xprt_needs_memalloc(struct rpc_xprt *xprt, struct rpc_task *tk)
{
if (!xprt)
return false;
if (!atomic_read(&xprt->swapper))
return false;
return test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task == tk;
}
/* /*
* This is the RPC `scheduler' (or rather, the finite state machine). * This is the RPC `scheduler' (or rather, the finite state machine).
*/ */
...@@ -884,6 +893,7 @@ static void __rpc_execute(struct rpc_task *task) ...@@ -884,6 +893,7 @@ static void __rpc_execute(struct rpc_task *task)
struct rpc_wait_queue *queue; struct rpc_wait_queue *queue;
int task_is_async = RPC_IS_ASYNC(task); int task_is_async = RPC_IS_ASYNC(task);
int status = 0; int status = 0;
unsigned long pflags = current->flags;
WARN_ON_ONCE(RPC_IS_QUEUED(task)); WARN_ON_ONCE(RPC_IS_QUEUED(task));
if (RPC_IS_QUEUED(task)) if (RPC_IS_QUEUED(task))
...@@ -906,6 +916,10 @@ static void __rpc_execute(struct rpc_task *task) ...@@ -906,6 +916,10 @@ static void __rpc_execute(struct rpc_task *task)
} }
if (!do_action) if (!do_action)
break; break;
if (RPC_IS_SWAPPER(task) ||
xprt_needs_memalloc(task->tk_xprt, task))
current->flags |= PF_MEMALLOC;
trace_rpc_task_run_action(task, do_action); trace_rpc_task_run_action(task, do_action);
do_action(task); do_action(task);
...@@ -943,7 +957,7 @@ static void __rpc_execute(struct rpc_task *task) ...@@ -943,7 +957,7 @@ static void __rpc_execute(struct rpc_task *task)
rpc_clear_running(task); rpc_clear_running(task);
spin_unlock(&queue->lock); spin_unlock(&queue->lock);
if (task_is_async) if (task_is_async)
return; goto out;
/* sync task: sleep here */ /* sync task: sleep here */
trace_rpc_task_sync_sleep(task, task->tk_action); trace_rpc_task_sync_sleep(task, task->tk_action);
...@@ -967,6 +981,8 @@ static void __rpc_execute(struct rpc_task *task) ...@@ -967,6 +981,8 @@ static void __rpc_execute(struct rpc_task *task)
/* Release all resources associated with the task */ /* Release all resources associated with the task */
rpc_release_task(task); rpc_release_task(task);
out:
current_restore_flags(pflags, PF_MEMALLOC);
} }
/* /*
...@@ -1021,15 +1037,15 @@ int rpc_malloc(struct rpc_task *task) ...@@ -1021,15 +1037,15 @@ int rpc_malloc(struct rpc_task *task)
struct rpc_rqst *rqst = task->tk_rqstp; struct rpc_rqst *rqst = task->tk_rqstp;
size_t size = rqst->rq_callsize + rqst->rq_rcvsize; size_t size = rqst->rq_callsize + rqst->rq_rcvsize;
struct rpc_buffer *buf; struct rpc_buffer *buf;
gfp_t gfp = GFP_NOFS; gfp_t gfp = rpc_task_gfp_mask();
if (RPC_IS_SWAPPER(task))
gfp = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN;
size += sizeof(struct rpc_buffer); size += sizeof(struct rpc_buffer);
if (size <= RPC_BUFFER_MAXSIZE) if (size <= RPC_BUFFER_MAXSIZE) {
buf = mempool_alloc(rpc_buffer_mempool, gfp); buf = kmem_cache_alloc(rpc_buffer_slabp, gfp);
else /* Reach for the mempool if dynamic allocation fails */
if (!buf && RPC_IS_ASYNC(task))
buf = mempool_alloc(rpc_buffer_mempool, GFP_NOWAIT);
} else
buf = kmalloc(size, gfp); buf = kmalloc(size, gfp);
if (!buf) if (!buf)
...@@ -1092,10 +1108,14 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta ...@@ -1092,10 +1108,14 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
rpc_init_task_statistics(task); rpc_init_task_statistics(task);
} }
static struct rpc_task * static struct rpc_task *rpc_alloc_task(void)
rpc_alloc_task(void)
{ {
return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); struct rpc_task *task;
task = kmem_cache_alloc(rpc_task_slabp, rpc_task_gfp_mask());
if (task)
return task;
return mempool_alloc(rpc_task_mempool, GFP_NOWAIT);
} }
/* /*
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xdr.h> #include <linux/sunrpc/xdr.h>
#include <linux/export.h> #include <linux/export.h>
...@@ -222,7 +223,7 @@ static int xprt_send_pagedata(struct socket *sock, struct msghdr *msg, ...@@ -222,7 +223,7 @@ static int xprt_send_pagedata(struct socket *sock, struct msghdr *msg,
{ {
int err; int err;
err = xdr_alloc_bvec(xdr, GFP_KERNEL); err = xdr_alloc_bvec(xdr, rpc_task_gfp_mask());
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -93,11 +93,14 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj, ...@@ -93,11 +93,14 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
ssize_t ret; ssize_t ret;
if (!xprt) if (!xprt) {
return 0; ret = sprintf(buf, "<closed>\n");
goto out;
}
ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
xprt_put(xprt); xprt_put(xprt);
return ret + 1; out:
return ret;
} }
static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj, static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
...@@ -105,41 +108,45 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj, ...@@ -105,41 +108,45 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
char *buf) char *buf)
{ {
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
struct sockaddr_storage saddr; size_t buflen = PAGE_SIZE;
struct sock_xprt *sock; ssize_t ret;
ssize_t ret = -1;
if (!xprt || !xprt_connected(xprt)) { if (!xprt || !xprt_connected(xprt)) {
xprt_put(xprt); ret = sprintf(buf, "<closed>\n");
return -ENOTCONN; } else if (xprt->ops->get_srcaddr) {
ret = xprt->ops->get_srcaddr(xprt, buf, buflen);
if (ret > 0) {
if (ret < buflen - 1) {
buf[ret] = '\n';
ret++;
buf[ret] = '\0';
} }
} else
sock = container_of(xprt, struct sock_xprt, xprt); ret = sprintf(buf, "<closed>\n");
mutex_lock(&sock->recv_mutex); } else
if (sock->sock == NULL || ret = sprintf(buf, "<not a socket>\n");
kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
goto out;
ret = sprintf(buf, "%pISc\n", &saddr);
out:
mutex_unlock(&sock->recv_mutex);
xprt_put(xprt); xprt_put(xprt);
return ret + 1; return ret;
} }
static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
struct kobj_attribute *attr, struct kobj_attribute *attr, char *buf)
char *buf)
{ {
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
unsigned short srcport = 0;
size_t buflen = PAGE_SIZE;
ssize_t ret; ssize_t ret;
if (!xprt || !xprt_connected(xprt)) { if (!xprt || !xprt_connected(xprt)) {
xprt_put(xprt); ret = sprintf(buf, "<closed>\n");
return -ENOTCONN; goto out;
} }
ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n" if (xprt->ops->get_srcport)
srcport = xprt->ops->get_srcport(xprt);
ret = snprintf(buf, buflen,
"last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
"max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n" "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
"binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n" "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
"backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n" "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
...@@ -147,14 +154,12 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, ...@@ -147,14 +154,12 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs, xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen, xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
xprt->sending.qlen, xprt->pending.qlen, xprt->sending.qlen, xprt->pending.qlen,
xprt->backlog.qlen, xprt->main, xprt->backlog.qlen, xprt->main, srcport,
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
get_srcport(xprt) : 0,
atomic_long_read(&xprt->queuelen), atomic_long_read(&xprt->queuelen),
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ? xprt->address_strings[RPC_DISPLAY_PORT]);
xprt->address_strings[RPC_DISPLAY_PORT] : "0"); out:
xprt_put(xprt); xprt_put(xprt);
return ret + 1; return ret;
} }
static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
...@@ -166,10 +171,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, ...@@ -166,10 +171,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
int locked, connected, connecting, close_wait, bound, binding, int locked, connected, connecting, close_wait, bound, binding,
closing, congested, cwnd_wait, write_space, offline, remove; closing, congested, cwnd_wait, write_space, offline, remove;
if (!xprt) if (!(xprt && xprt->state)) {
return 0;
if (!xprt->state) {
ret = sprintf(buf, "state=CLOSED\n"); ret = sprintf(buf, "state=CLOSED\n");
} else { } else {
locked = test_bit(XPRT_LOCKED, &xprt->state); locked = test_bit(XPRT_LOCKED, &xprt->state);
...@@ -201,7 +203,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj, ...@@ -201,7 +203,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
} }
xprt_put(xprt); xprt_put(xprt);
return ret + 1; return ret;
} }
static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
...@@ -220,7 +222,7 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj, ...@@ -220,7 +222,7 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
xprt_switch->xps_nunique_destaddr_xprts, xprt_switch->xps_nunique_destaddr_xprts,
atomic_long_read(&xprt_switch->xps_queuelen)); atomic_long_read(&xprt_switch->xps_queuelen));
xprt_switch_put(xprt_switch); xprt_switch_put(xprt_switch);
return ret + 1; return ret;
} }
static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
......
...@@ -1354,17 +1354,6 @@ xprt_request_enqueue_transmit(struct rpc_task *task) ...@@ -1354,17 +1354,6 @@ xprt_request_enqueue_transmit(struct rpc_task *task)
INIT_LIST_HEAD(&req->rq_xmit2); INIT_LIST_HEAD(&req->rq_xmit2);
goto out; goto out;
} }
} else if (RPC_IS_SWAPPER(task)) {
list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
if (pos->rq_cong || pos->rq_bytes_sent)
continue;
if (RPC_IS_SWAPPER(pos->rq_task))
continue;
/* Note: req is added _before_ pos */
list_add_tail(&req->rq_xmit, &pos->rq_xmit);
INIT_LIST_HEAD(&req->rq_xmit2);
goto out;
}
} else if (!req->rq_seqno) { } else if (!req->rq_seqno) {
list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
if (pos->rq_task->tk_owner != task->tk_owner) if (pos->rq_task->tk_owner != task->tk_owner)
...@@ -1503,6 +1492,9 @@ bool xprt_prepare_transmit(struct rpc_task *task) ...@@ -1503,6 +1492,9 @@ bool xprt_prepare_transmit(struct rpc_task *task)
return false; return false;
} }
if (atomic_read(&xprt->swapper))
/* This will be clear in __rpc_execute */
current->flags |= PF_MEMALLOC;
return true; return true;
} }
...@@ -1692,7 +1684,7 @@ static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt) ...@@ -1692,7 +1684,7 @@ static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt)
goto out; goto out;
++xprt->num_reqs; ++xprt->num_reqs;
spin_unlock(&xprt->reserve_lock); spin_unlock(&xprt->reserve_lock);
req = kzalloc(sizeof(struct rpc_rqst), GFP_NOFS); req = kzalloc(sizeof(*req), rpc_task_gfp_mask());
spin_lock(&xprt->reserve_lock); spin_lock(&xprt->reserve_lock);
if (req != NULL) if (req != NULL)
goto out; goto out;
...@@ -2112,7 +2104,14 @@ static void xprt_destroy(struct rpc_xprt *xprt) ...@@ -2112,7 +2104,14 @@ static void xprt_destroy(struct rpc_xprt *xprt)
*/ */
wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE); wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE);
/*
* xprt_schedule_autodisconnect() can run after XPRT_LOCKED
* is cleared. We use ->transport_lock to ensure the mod_timer()
* can only run *before* del_time_sync(), never after.
*/
spin_lock(&xprt->transport_lock);
del_timer_sync(&xprt->timer); del_timer_sync(&xprt->timer);
spin_unlock(&xprt->transport_lock);
/* /*
* Destroy sockets etc from the system workqueue so they can * Destroy sockets etc from the system workqueue so they can
......
...@@ -130,7 +130,7 @@ int frwr_mr_init(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr *mr) ...@@ -130,7 +130,7 @@ int frwr_mr_init(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr *mr)
if (IS_ERR(frmr)) if (IS_ERR(frmr))
goto out_mr_err; goto out_mr_err;
sg = kmalloc_array(depth, sizeof(*sg), GFP_NOFS); sg = kmalloc_array(depth, sizeof(*sg), GFP_KERNEL);
if (!sg) if (!sg)
goto out_list_err; goto out_list_err;
......
...@@ -235,8 +235,11 @@ xprt_rdma_connect_worker(struct work_struct *work) ...@@ -235,8 +235,11 @@ xprt_rdma_connect_worker(struct work_struct *work)
struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt, struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt,
rx_connect_worker.work); rx_connect_worker.work);
struct rpc_xprt *xprt = &r_xprt->rx_xprt; struct rpc_xprt *xprt = &r_xprt->rx_xprt;
unsigned int pflags = current->flags;
int rc; int rc;
if (atomic_read(&xprt->swapper))
current->flags |= PF_MEMALLOC;
rc = rpcrdma_xprt_connect(r_xprt); rc = rpcrdma_xprt_connect(r_xprt);
xprt_clear_connecting(xprt); xprt_clear_connecting(xprt);
if (!rc) { if (!rc) {
...@@ -250,6 +253,7 @@ xprt_rdma_connect_worker(struct work_struct *work) ...@@ -250,6 +253,7 @@ xprt_rdma_connect_worker(struct work_struct *work)
rpcrdma_xprt_disconnect(r_xprt); rpcrdma_xprt_disconnect(r_xprt);
xprt_unlock_connect(xprt, r_xprt); xprt_unlock_connect(xprt, r_xprt);
xprt_wake_pending_tasks(xprt, rc); xprt_wake_pending_tasks(xprt, rc);
current_restore_flags(pflags, PF_MEMALLOC);
} }
/** /**
...@@ -517,7 +521,7 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -517,7 +521,7 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
return; return;
out_sleep: out_sleep:
task->tk_status = -EAGAIN; task->tk_status = -ENOMEM;
xprt_add_backlog(xprt, task); xprt_add_backlog(xprt, task);
} }
...@@ -570,8 +574,8 @@ xprt_rdma_allocate(struct rpc_task *task) ...@@ -570,8 +574,8 @@ xprt_rdma_allocate(struct rpc_task *task)
gfp_t flags; gfp_t flags;
flags = RPCRDMA_DEF_GFP; flags = RPCRDMA_DEF_GFP;
if (RPC_IS_SWAPPER(task)) if (RPC_IS_ASYNC(task))
flags = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN; flags = GFP_NOWAIT | __GFP_NOWARN;
if (!rpcrdma_check_regbuf(r_xprt, req->rl_sendbuf, rqst->rq_callsize, if (!rpcrdma_check_regbuf(r_xprt, req->rl_sendbuf, rqst->rq_callsize,
flags)) flags))
......
...@@ -373,7 +373,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt) ...@@ -373,7 +373,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
struct rpcrdma_ep *ep; struct rpcrdma_ep *ep;
int rc; int rc;
ep = kzalloc(sizeof(*ep), GFP_NOFS); ep = kzalloc(sizeof(*ep), GFP_KERNEL);
if (!ep) if (!ep)
return -ENOTCONN; return -ENOTCONN;
ep->re_xprt = &r_xprt->rx_xprt; ep->re_xprt = &r_xprt->rx_xprt;
...@@ -746,7 +746,7 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt) ...@@ -746,7 +746,7 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
struct rpcrdma_mr *mr; struct rpcrdma_mr *mr;
int rc; int rc;
mr = kzalloc(sizeof(*mr), GFP_NOFS); mr = kzalloc(sizeof(*mr), GFP_KERNEL);
if (!mr) if (!mr)
break; break;
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "sunrpc.h" #include "sunrpc.h"
static void xs_close(struct rpc_xprt *xprt); static void xs_close(struct rpc_xprt *xprt);
static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock);
static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
struct socket *sock); struct socket *sock);
...@@ -427,9 +428,9 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, ...@@ -427,9 +428,9 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
offset += want; offset += want;
} }
want = xs_alloc_sparse_pages(buf, want = xs_alloc_sparse_pages(
min_t(size_t, count - offset, buf->page_len), buf, min_t(size_t, count - offset, buf->page_len),
GFP_KERNEL); GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
if (seek < want) { if (seek < want) {
ret = xs_read_bvec(sock, msg, flags, buf->bvec, ret = xs_read_bvec(sock, msg, flags, buf->bvec,
xdr_buf_pagecount(buf), xdr_buf_pagecount(buf),
...@@ -763,12 +764,12 @@ xs_stream_start_connect(struct sock_xprt *transport) ...@@ -763,12 +764,12 @@ xs_stream_start_connect(struct sock_xprt *transport)
/** /**
* xs_nospace - handle transmit was incomplete * xs_nospace - handle transmit was incomplete
* @req: pointer to RPC request * @req: pointer to RPC request
* @transport: pointer to struct sock_xprt
* *
*/ */
static int xs_nospace(struct rpc_rqst *req) static int xs_nospace(struct rpc_rqst *req, struct sock_xprt *transport)
{ {
struct rpc_xprt *xprt = req->rq_xprt; struct rpc_xprt *xprt = &transport->xprt;
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct sock *sk = transport->inet; struct sock *sk = transport->inet;
int ret = -EAGAIN; int ret = -EAGAIN;
...@@ -780,24 +781,44 @@ static int xs_nospace(struct rpc_rqst *req) ...@@ -780,24 +781,44 @@ static int xs_nospace(struct rpc_rqst *req)
/* Don't race with disconnect */ /* Don't race with disconnect */
if (xprt_connected(xprt)) { if (xprt_connected(xprt)) {
/* wait for more buffer space */ /* wait for more buffer space */
set_bit(XPRT_SOCK_NOSPACE, &transport->sock_state);
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
sk->sk_write_pending++; sk->sk_write_pending++;
xprt_wait_for_buffer_space(xprt); xprt_wait_for_buffer_space(xprt);
} else } else
ret = -ENOTCONN; ret = -ENOTCONN;
spin_unlock(&xprt->transport_lock); spin_unlock(&xprt->transport_lock);
return ret;
}
/* Race breaker in case memory is freed before above code is called */ static int xs_sock_nospace(struct rpc_rqst *req)
if (ret == -EAGAIN) { {
struct socket_wq *wq; struct sock_xprt *transport =
container_of(req->rq_xprt, struct sock_xprt, xprt);
struct sock *sk = transport->inet;
int ret = -EAGAIN;
rcu_read_lock(); lock_sock(sk);
wq = rcu_dereference(sk->sk_wq); if (!sock_writeable(sk))
set_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags); ret = xs_nospace(req, transport);
rcu_read_unlock(); release_sock(sk);
return ret;
}
sk->sk_write_space(sk); static int xs_stream_nospace(struct rpc_rqst *req, bool vm_wait)
} {
struct sock_xprt *transport =
container_of(req->rq_xprt, struct sock_xprt, xprt);
struct sock *sk = transport->inet;
int ret = -EAGAIN;
if (vm_wait)
return -ENOBUFS;
lock_sock(sk);
if (!sk_stream_memory_free(sk))
ret = xs_nospace(req, transport);
release_sock(sk);
return ret; return ret;
} }
...@@ -805,7 +826,8 @@ static void ...@@ -805,7 +826,8 @@ static void
xs_stream_prepare_request(struct rpc_rqst *req) xs_stream_prepare_request(struct rpc_rqst *req)
{ {
xdr_free_bvec(&req->rq_rcv_buf); xdr_free_bvec(&req->rq_rcv_buf);
req->rq_task->tk_status = xdr_alloc_bvec(&req->rq_rcv_buf, GFP_KERNEL); req->rq_task->tk_status = xdr_alloc_bvec(
&req->rq_rcv_buf, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
} }
/* /*
...@@ -851,6 +873,7 @@ static int xs_local_send_request(struct rpc_rqst *req) ...@@ -851,6 +873,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
struct msghdr msg = { struct msghdr msg = {
.msg_flags = XS_SENDMSG_FLAGS, .msg_flags = XS_SENDMSG_FLAGS,
}; };
bool vm_wait;
unsigned int sent; unsigned int sent;
int status; int status;
...@@ -863,15 +886,14 @@ static int xs_local_send_request(struct rpc_rqst *req) ...@@ -863,15 +886,14 @@ static int xs_local_send_request(struct rpc_rqst *req)
xs_pktdump("packet data:", xs_pktdump("packet data:",
req->rq_svec->iov_base, req->rq_svec->iov_len); req->rq_svec->iov_base, req->rq_svec->iov_len);
vm_wait = sk_stream_is_writeable(transport->inet) ? true : false;
req->rq_xtime = ktime_get(); req->rq_xtime = ktime_get();
status = xprt_sock_sendmsg(transport->sock, &msg, xdr, status = xprt_sock_sendmsg(transport->sock, &msg, xdr,
transport->xmit.offset, rm, &sent); transport->xmit.offset, rm, &sent);
dprintk("RPC: %s(%u) = %d\n", dprintk("RPC: %s(%u) = %d\n",
__func__, xdr->len - transport->xmit.offset, status); __func__, xdr->len - transport->xmit.offset, status);
if (status == -EAGAIN && sock_writeable(transport->inet))
status = -ENOBUFS;
if (likely(sent > 0) || status == 0) { if (likely(sent > 0) || status == 0) {
transport->xmit.offset += sent; transport->xmit.offset += sent;
req->rq_bytes_sent = transport->xmit.offset; req->rq_bytes_sent = transport->xmit.offset;
...@@ -881,13 +903,12 @@ static int xs_local_send_request(struct rpc_rqst *req) ...@@ -881,13 +903,12 @@ static int xs_local_send_request(struct rpc_rqst *req)
return 0; return 0;
} }
status = -EAGAIN; status = -EAGAIN;
vm_wait = false;
} }
switch (status) { switch (status) {
case -ENOBUFS:
break;
case -EAGAIN: case -EAGAIN:
status = xs_nospace(req); status = xs_stream_nospace(req, vm_wait);
break; break;
default: default:
dprintk("RPC: sendmsg returned unrecognized error %d\n", dprintk("RPC: sendmsg returned unrecognized error %d\n",
...@@ -963,7 +984,7 @@ static int xs_udp_send_request(struct rpc_rqst *req) ...@@ -963,7 +984,7 @@ static int xs_udp_send_request(struct rpc_rqst *req)
/* Should we call xs_close() here? */ /* Should we call xs_close() here? */
break; break;
case -EAGAIN: case -EAGAIN:
status = xs_nospace(req); status = xs_sock_nospace(req);
break; break;
case -ENETUNREACH: case -ENETUNREACH:
case -ENOBUFS: case -ENOBUFS:
...@@ -1005,7 +1026,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req) ...@@ -1005,7 +1026,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
struct msghdr msg = { struct msghdr msg = {
.msg_flags = XS_SENDMSG_FLAGS, .msg_flags = XS_SENDMSG_FLAGS,
}; };
bool vm_wait = false; bool vm_wait;
unsigned int sent; unsigned int sent;
int status; int status;
...@@ -1025,12 +1046,17 @@ static int xs_tcp_send_request(struct rpc_rqst *req) ...@@ -1025,12 +1046,17 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state)) if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state))
xs_tcp_set_socket_timeouts(xprt, transport->sock); xs_tcp_set_socket_timeouts(xprt, transport->sock);
xs_set_srcport(transport, transport->sock);
/* Continue transmitting the packet/record. We must be careful /* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have * to cope with writespace callbacks arriving _after_ we have
* called sendmsg(). */ * called sendmsg(). */
req->rq_xtime = ktime_get(); req->rq_xtime = ktime_get();
tcp_sock_set_cork(transport->inet, true); tcp_sock_set_cork(transport->inet, true);
while (1) {
vm_wait = sk_stream_is_writeable(transport->inet) ? true : false;
do {
status = xprt_sock_sendmsg(transport->sock, &msg, xdr, status = xprt_sock_sendmsg(transport->sock, &msg, xdr,
transport->xmit.offset, rm, &sent); transport->xmit.offset, rm, &sent);
...@@ -1051,31 +1077,10 @@ static int xs_tcp_send_request(struct rpc_rqst *req) ...@@ -1051,31 +1077,10 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
WARN_ON_ONCE(sent == 0 && status == 0); WARN_ON_ONCE(sent == 0 && status == 0);
if (status == -EAGAIN ) { if (sent > 0)
/*
* Return EAGAIN if we're sure we're hitting the
* socket send buffer limits.
*/
if (test_bit(SOCK_NOSPACE, &transport->sock->flags))
break;
/*
* Did we hit a memory allocation failure?
*/
if (sent == 0) {
status = -ENOBUFS;
if (vm_wait)
break;
/* Retry, knowing now that we're below the
* socket send buffer limit
*/
vm_wait = true;
}
continue;
}
if (status < 0)
break;
vm_wait = false; vm_wait = false;
}
} while (status == 0);
switch (status) { switch (status) {
case -ENOTSOCK: case -ENOTSOCK:
...@@ -1083,7 +1088,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req) ...@@ -1083,7 +1088,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
/* Should we call xs_close() here? */ /* Should we call xs_close() here? */
break; break;
case -EAGAIN: case -EAGAIN:
status = xs_nospace(req); status = xs_stream_nospace(req, vm_wait);
break; break;
case -ECONNRESET: case -ECONNRESET:
case -ECONNREFUSED: case -ECONNREFUSED:
...@@ -1124,6 +1129,7 @@ static void xs_sock_reset_state_flags(struct rpc_xprt *xprt) ...@@ -1124,6 +1129,7 @@ static void xs_sock_reset_state_flags(struct rpc_xprt *xprt)
clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state); clear_bit(XPRT_SOCK_WAKE_ERROR, &transport->sock_state);
clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state); clear_bit(XPRT_SOCK_WAKE_WRITE, &transport->sock_state);
clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state); clear_bit(XPRT_SOCK_WAKE_DISCONNECT, &transport->sock_state);
clear_bit(XPRT_SOCK_NOSPACE, &transport->sock_state);
} }
static void xs_run_error_worker(struct sock_xprt *transport, unsigned int nr) static void xs_run_error_worker(struct sock_xprt *transport, unsigned int nr)
...@@ -1470,7 +1476,6 @@ static void xs_tcp_state_change(struct sock *sk) ...@@ -1470,7 +1476,6 @@ static void xs_tcp_state_change(struct sock *sk)
static void xs_write_space(struct sock *sk) static void xs_write_space(struct sock *sk)
{ {
struct socket_wq *wq;
struct sock_xprt *transport; struct sock_xprt *transport;
struct rpc_xprt *xprt; struct rpc_xprt *xprt;
...@@ -1481,15 +1486,10 @@ static void xs_write_space(struct sock *sk) ...@@ -1481,15 +1486,10 @@ static void xs_write_space(struct sock *sk)
if (unlikely(!(xprt = xprt_from_sock(sk)))) if (unlikely(!(xprt = xprt_from_sock(sk))))
return; return;
transport = container_of(xprt, struct sock_xprt, xprt); transport = container_of(xprt, struct sock_xprt, xprt);
rcu_read_lock(); if (!test_and_clear_bit(XPRT_SOCK_NOSPACE, &transport->sock_state))
wq = rcu_dereference(sk->sk_wq); return;
if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
goto out;
xs_run_error_worker(transport, XPRT_SOCK_WAKE_WRITE); xs_run_error_worker(transport, XPRT_SOCK_WAKE_WRITE);
sk->sk_write_pending--; sk->sk_write_pending--;
out:
rcu_read_unlock();
} }
/** /**
...@@ -1638,7 +1638,7 @@ static int xs_get_srcport(struct sock_xprt *transport) ...@@ -1638,7 +1638,7 @@ static int xs_get_srcport(struct sock_xprt *transport)
return port; return port;
} }
unsigned short get_srcport(struct rpc_xprt *xprt) static unsigned short xs_sock_srcport(struct rpc_xprt *xprt)
{ {
struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt); struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
unsigned short ret = 0; unsigned short ret = 0;
...@@ -1648,7 +1648,25 @@ unsigned short get_srcport(struct rpc_xprt *xprt) ...@@ -1648,7 +1648,25 @@ unsigned short get_srcport(struct rpc_xprt *xprt)
mutex_unlock(&sock->recv_mutex); mutex_unlock(&sock->recv_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL(get_srcport);
static int xs_sock_srcaddr(struct rpc_xprt *xprt, char *buf, size_t buflen)
{
struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
union {
struct sockaddr sa;
struct sockaddr_storage st;
} saddr;
int ret = -ENOTCONN;
mutex_lock(&sock->recv_mutex);
if (sock->sock) {
ret = kernel_getsockname(sock->sock, &saddr.sa);
if (ret >= 0)
ret = snprintf(buf, buflen, "%pISc", &saddr.sa);
}
mutex_unlock(&sock->recv_mutex);
return ret;
}
static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port) static unsigned short xs_next_srcport(struct sock_xprt *transport, unsigned short port)
{ {
...@@ -1830,7 +1848,6 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, ...@@ -1830,7 +1848,6 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,
sk->sk_user_data = xprt; sk->sk_user_data = xprt;
sk->sk_data_ready = xs_data_ready; sk->sk_data_ready = xs_data_ready;
sk->sk_write_space = xs_udp_write_space; sk->sk_write_space = xs_udp_write_space;
sock_set_flag(sk, SOCK_FASYNC);
sk->sk_error_report = xs_error_report; sk->sk_error_report = xs_error_report;
xprt_clear_connected(xprt); xprt_clear_connected(xprt);
...@@ -1936,9 +1953,9 @@ static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -1936,9 +1953,9 @@ static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task)
#if IS_ENABLED(CONFIG_SUNRPC_SWAP) #if IS_ENABLED(CONFIG_SUNRPC_SWAP)
/* /*
* Note that this should be called with XPRT_LOCKED held (or when we otherwise * Note that this should be called with XPRT_LOCKED held, or recv_mutex
* know that we have exclusive access to the socket), to guard against * held, or when we otherwise know that we have exclusive access to the
* races with xs_reset_transport. * socket, to guard against races with xs_reset_transport.
*/ */
static void xs_set_memalloc(struct rpc_xprt *xprt) static void xs_set_memalloc(struct rpc_xprt *xprt)
{ {
...@@ -1967,13 +1984,11 @@ xs_enable_swap(struct rpc_xprt *xprt) ...@@ -1967,13 +1984,11 @@ xs_enable_swap(struct rpc_xprt *xprt)
{ {
struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt); struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt);
if (atomic_inc_return(&xprt->swapper) != 1) mutex_lock(&xs->recv_mutex);
return 0; if (atomic_inc_return(&xprt->swapper) == 1 &&
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) xs->inet)
return -ERESTARTSYS;
if (xs->inet)
sk_set_memalloc(xs->inet); sk_set_memalloc(xs->inet);
xprt_release_xprt(xprt, NULL); mutex_unlock(&xs->recv_mutex);
return 0; return 0;
} }
...@@ -1989,13 +2004,11 @@ xs_disable_swap(struct rpc_xprt *xprt) ...@@ -1989,13 +2004,11 @@ xs_disable_swap(struct rpc_xprt *xprt)
{ {
struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt); struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt);
if (!atomic_dec_and_test(&xprt->swapper)) mutex_lock(&xs->recv_mutex);
return; if (atomic_dec_and_test(&xprt->swapper) &&
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) xs->inet)
return;
if (xs->inet)
sk_clear_memalloc(xs->inet); sk_clear_memalloc(xs->inet);
xprt_release_xprt(xprt, NULL); mutex_unlock(&xs->recv_mutex);
} }
#else #else
static void xs_set_memalloc(struct rpc_xprt *xprt) static void xs_set_memalloc(struct rpc_xprt *xprt)
...@@ -2028,7 +2041,6 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) ...@@ -2028,7 +2041,6 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
sk->sk_user_data = xprt; sk->sk_user_data = xprt;
sk->sk_data_ready = xs_data_ready; sk->sk_data_ready = xs_data_ready;
sk->sk_write_space = xs_udp_write_space; sk->sk_write_space = xs_udp_write_space;
sock_set_flag(sk, SOCK_FASYNC);
xprt_set_connected(xprt); xprt_set_connected(xprt);
...@@ -2052,7 +2064,10 @@ static void xs_udp_setup_socket(struct work_struct *work) ...@@ -2052,7 +2064,10 @@ static void xs_udp_setup_socket(struct work_struct *work)
struct rpc_xprt *xprt = &transport->xprt; struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock; struct socket *sock;
int status = -EIO; int status = -EIO;
unsigned int pflags = current->flags;
if (atomic_read(&xprt->swapper))
current->flags |= PF_MEMALLOC;
sock = xs_create_sock(xprt, transport, sock = xs_create_sock(xprt, transport,
xs_addr(xprt)->sa_family, SOCK_DGRAM, xs_addr(xprt)->sa_family, SOCK_DGRAM,
IPPROTO_UDP, false); IPPROTO_UDP, false);
...@@ -2072,6 +2087,7 @@ static void xs_udp_setup_socket(struct work_struct *work) ...@@ -2072,6 +2087,7 @@ static void xs_udp_setup_socket(struct work_struct *work)
xprt_clear_connecting(xprt); xprt_clear_connecting(xprt);
xprt_unlock_connect(xprt, transport); xprt_unlock_connect(xprt, transport);
xprt_wake_pending_tasks(xprt, status); xprt_wake_pending_tasks(xprt, status);
current_restore_flags(pflags, PF_MEMALLOC);
} }
/** /**
...@@ -2191,7 +2207,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) ...@@ -2191,7 +2207,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
sk->sk_data_ready = xs_data_ready; sk->sk_data_ready = xs_data_ready;
sk->sk_state_change = xs_tcp_state_change; sk->sk_state_change = xs_tcp_state_change;
sk->sk_write_space = xs_tcp_write_space; sk->sk_write_space = xs_tcp_write_space;
sock_set_flag(sk, SOCK_FASYNC);
sk->sk_error_report = xs_error_report; sk->sk_error_report = xs_error_report;
/* socket options */ /* socket options */
...@@ -2231,11 +2246,19 @@ static void xs_tcp_setup_socket(struct work_struct *work) ...@@ -2231,11 +2246,19 @@ static void xs_tcp_setup_socket(struct work_struct *work)
struct socket *sock = transport->sock; struct socket *sock = transport->sock;
struct rpc_xprt *xprt = &transport->xprt; struct rpc_xprt *xprt = &transport->xprt;
int status; int status;
unsigned int pflags = current->flags;
if (!sock) { if (atomic_read(&xprt->swapper))
sock = xs_create_sock(xprt, transport, current->flags |= PF_MEMALLOC;
xs_addr(xprt)->sa_family, SOCK_STREAM,
IPPROTO_TCP, true); if (xprt_connected(xprt))
goto out;
if (test_and_clear_bit(XPRT_SOCK_CONNECT_SENT,
&transport->sock_state) ||
!sock) {
xs_reset_transport(transport);
sock = xs_create_sock(xprt, transport, xs_addr(xprt)->sa_family,
SOCK_STREAM, IPPROTO_TCP, true);
if (IS_ERR(sock)) { if (IS_ERR(sock)) {
xprt_wake_pending_tasks(xprt, PTR_ERR(sock)); xprt_wake_pending_tasks(xprt, PTR_ERR(sock));
goto out; goto out;
...@@ -2255,10 +2278,9 @@ static void xs_tcp_setup_socket(struct work_struct *work) ...@@ -2255,10 +2278,9 @@ static void xs_tcp_setup_socket(struct work_struct *work)
sock->sk->sk_state); sock->sk->sk_state);
switch (status) { switch (status) {
case 0: case 0:
xs_set_srcport(transport, sock);
fallthrough;
case -EINPROGRESS: case -EINPROGRESS:
/* SYN_SENT! */ /* SYN_SENT! */
set_bit(XPRT_SOCK_CONNECT_SENT, &transport->sock_state);
if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
fallthrough; fallthrough;
...@@ -2296,6 +2318,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) ...@@ -2296,6 +2318,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
xprt_clear_connecting(xprt); xprt_clear_connecting(xprt);
out_unlock: out_unlock:
xprt_unlock_connect(xprt, transport); xprt_unlock_connect(xprt, transport);
current_restore_flags(pflags, PF_MEMALLOC);
} }
/** /**
...@@ -2319,13 +2342,9 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -2319,13 +2342,9 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport)); WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport));
if (transport->sock != NULL && !xprt_connecting(xprt)) { if (transport->sock != NULL) {
dprintk("RPC: xs_connect delayed xprt %p for %lu " dprintk("RPC: xs_connect delayed xprt %p for %lu "
"seconds\n", "seconds\n", xprt, xprt->reestablish_timeout / HZ);
xprt, xprt->reestablish_timeout / HZ);
/* Start by resetting any existing state */
xs_reset_transport(transport);
delay = xprt_reconnect_delay(xprt); delay = xprt_reconnect_delay(xprt);
xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO); xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO);
...@@ -2487,7 +2506,7 @@ static int bc_malloc(struct rpc_task *task) ...@@ -2487,7 +2506,7 @@ static int bc_malloc(struct rpc_task *task)
return -EINVAL; return -EINVAL;
} }
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
...@@ -2621,6 +2640,8 @@ static const struct rpc_xprt_ops xs_udp_ops = { ...@@ -2621,6 +2640,8 @@ static const struct rpc_xprt_ops xs_udp_ops = {
.rpcbind = rpcb_getport_async, .rpcbind = rpcb_getport_async,
.set_port = xs_set_port, .set_port = xs_set_port,
.connect = xs_connect, .connect = xs_connect,
.get_srcaddr = xs_sock_srcaddr,
.get_srcport = xs_sock_srcport,
.buf_alloc = rpc_malloc, .buf_alloc = rpc_malloc,
.buf_free = rpc_free, .buf_free = rpc_free,
.send_request = xs_udp_send_request, .send_request = xs_udp_send_request,
...@@ -2643,6 +2664,8 @@ static const struct rpc_xprt_ops xs_tcp_ops = { ...@@ -2643,6 +2664,8 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
.rpcbind = rpcb_getport_async, .rpcbind = rpcb_getport_async,
.set_port = xs_set_port, .set_port = xs_set_port,
.connect = xs_connect, .connect = xs_connect,
.get_srcaddr = xs_sock_srcaddr,
.get_srcport = xs_sock_srcport,
.buf_alloc = rpc_malloc, .buf_alloc = rpc_malloc,
.buf_free = rpc_free, .buf_free = rpc_free,
.prepare_request = xs_stream_prepare_request, .prepare_request = xs_stream_prepare_request,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册