NFS client updates for Linux 5.18

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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmJDLLUACgkQZwvnipYK
 APJZ5Q/9FH5S38RcUOxpFS+XaVdmxltJTMQv9Bz5mcyljq6PwRjTn73Qs7MfBQfD
 k90O9Pn/EXgQpFWNW4o/saQGLAO1MbVaesdNNF92Le9NziMz7lr95fsFXOqpg9EQ
 rEVOImWinv/N0+P0yv5tgjx6Fheu70L4dnwsxepnmtv2R1VjXOVchK7WjsV+9qey
 Xvn15OzhtVCGhRvvKfmGuGW+2I0D29tRNn2X0Pi+LjxAEQ0We/rcsJeGDMGYtbeC
 2U4ADk7KB0kJq04WYCH8k8tTrljL3PUONzO6QP1lltmAZ0FOwXf/AjyaD3SML2Xu
 A1yc2bEn3/S6wCQ3BiMxoE7UCSewg/ZyQD7B9GjZ/nWYNXREhLKvtVZt+ULTCA6o
 UKAI2vlEHljzQI2YfbVVZFyL8KCZqi+BFcJ/H/dtFKNazIkiefkaF+703Pflazis
 HjhA5G6IT0Pk6qZ6OBp+Z/4kCDYZYXXi9ysiNuMPWCiYEfZzt7ocUjm44uRAi+vR
 Qpf0V01Rg4iplTj3YFXqb9TwxrudzC7AcQ7hbLJia0kD/8djG+aGZs3SJWeO+VuE
 Xa41oxAx9jqOSRvSKPvj7nbexrwn8PtQI2NtDRqjPXlg6+Jbk23u8lIEVhsCH877
 xoMUHtTKLyqECskzRN4nh7qoBD3QfiLuI74aDcPtGEuXzU1+Ox8=
 =jeGt
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2022-03-29 18:55:37 -07:00
commit 965181d7ef
60 changed files with 1325 additions and 821 deletions

View File

@ -4,6 +4,10 @@ config NFS_FS
depends on INET && FILE_LOCKING && MULTIUSER
select LOCKD
select SUNRPC
select CRYPTO
select CRYPTO_HASH
select XXHASH
select CRYPTO_XXHASH
select NFS_ACL_SUPPORT if NFS_V3_ACL
help
Choose Y here if you want to access files residing on other

View File

@ -358,12 +358,11 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
struct cb_process_state *cps)
{
struct cb_devicenotifyargs *args = argp;
const struct pnfs_layoutdriver_type *ld = NULL;
uint32_t i;
__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);
goto out;
}
@ -371,23 +370,15 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
for (i = 0; i < args->ndevs; i++) {
struct cb_devicenotifyitem *dev = &args->devs[i];
if (!server ||
server->pnfs_curr_ld->id != dev->cbd_layout_type) {
rcu_read_lock();
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
if (server->pnfs_curr_ld &&
server->pnfs_curr_ld->id == dev->cbd_layout_type) {
rcu_read_unlock();
goto found;
}
rcu_read_unlock();
continue;
if (!ld || ld->id != dev->cbd_layout_type) {
pnfs_put_layoutdriver(ld);
ld = pnfs_find_layoutdriver(dev->cbd_layout_type);
if (!ld)
continue;
}
found:
nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id);
}
pnfs_put_layoutdriver(ld);
out:
kfree(args->devs);
return res;
@ -710,7 +701,7 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
struct nfs4_copy_state *copy, *tmp_copy;
bool found = false;
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL);
if (!copy)
return htonl(NFS4ERR_SERVERFAULT);

View File

@ -271,10 +271,6 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
n = ntohl(*p++);
if (n == 0)
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);
if (!args->devs) {

View File

@ -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 &&
(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);
if (error < 0)
return error;

View File

@ -439,7 +439,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
struct nfs_delegation *freeme = NULL;
int status = 0;
delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
delegation = kmalloc(sizeof(*delegation), GFP_KERNEL_ACCOUNT);
if (delegation == NULL)
return -ENOMEM;
nfs4_stateid_copy(&delegation->stateid, stateid);

File diff suppressed because it is too large Load Diff

View File

@ -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);
if (iov_iter_rw(iter) == READ)
return nfs_file_direct_read(iocb, iter);
return nfs_file_direct_write(iocb, iter);
return nfs_file_direct_read(iocb, iter, true);
return nfs_file_direct_write(iocb, iter, true);
}
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,
* nfs_file_direct_read - file direct read operation for NFS files
* @iocb: target I/O control block
* @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
* 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,
* client must read the updated atime from the server back into its
* 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 address_space *mapping = file->f_mapping;
@ -482,12 +484,14 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
if (iter_is_iovec(iter))
dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;
nfs_start_io_direct(inode);
if (!swap)
nfs_start_io_direct(inode);
NFS_I(inode)->read_io += count;
requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
nfs_end_io_direct(inode);
if (!swap)
nfs_end_io_direct(inode);
if (requested > 0) {
result = nfs_direct_wait(dreq);
@ -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,
struct iov_iter *iter,
loff_t pos)
loff_t pos, int ioflags)
{
struct nfs_pageio_descriptor desc;
struct inode *inode = dreq->inode;
@ -798,7 +802,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
size_t requested_bytes = 0;
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);
desc.pg_dreq = dreq;
get_dreq(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
* @iocb: target I/O control block
* @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
* 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,
* Note that O_APPEND is not supported for NFS direct writes, as there
* 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;
size_t count;
@ -906,7 +912,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n",
file, iov_iter_count(iter), (long long) iocb->ki_pos);
result = generic_write_checks(iocb, iter);
if (swap)
/* bypass generic checks */
result = iov_iter_count(iter);
else
result = generic_write_checks(iocb, iter);
if (result <= 0)
return result;
count = result;
@ -937,17 +947,23 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
dreq->iocb = iocb;
pnfs_init_ds_commit_info_ops(&dreq->ds_cinfo, inode);
nfs_start_io_direct(inode);
if (swap) {
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
FLUSH_STABLE);
} else {
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) {
invalidate_inode_pages2_range(mapping,
pos >> PAGE_SHIFT, end);
if (mapping->nrpages) {
invalidate_inode_pages2_range(mapping,
pos >> PAGE_SHIFT, end);
}
nfs_end_io_direct(inode);
}
nfs_end_io_direct(inode);
if (requested > 0) {
result = nfs_direct_wait(dreq);
if (result > 0) {

View File

@ -44,11 +44,6 @@
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)
{
if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
@ -162,7 +157,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
ssize_t result;
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",
iocb->ki_filp,
@ -488,8 +483,9 @@ static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
{
unsigned long blocks;
long long isize;
struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host);
struct inode *inode = 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;
spin_lock(&inode->i_lock);
blocks = inode->i_blocks;
@ -502,19 +498,27 @@ static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
*span = sis->pages;
if (cl->rpc_ops->enable_swap)
cl->rpc_ops->enable_swap(inode);
return rpc_clnt_swap_activate(clnt);
}
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);
if (cl->rpc_ops->disable_swap)
cl->rpc_ops->disable_swap(file_inode(file));
}
const struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage,
.readpages = nfs_readpages,
.readahead = nfs_readahead,
.dirty_folio = filemap_dirty_folio,
.writepage = nfs_writepage,
.writepages = nfs_writepages,
@ -619,7 +623,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
return result;
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",
file, iov_iter_count(from), (long long) iocb->ki_pos);

View File

@ -1075,7 +1075,7 @@ filelayout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
unsigned int size = (fl->stripe_type == STRIPE_SPARSE) ?
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) {
spin_lock(&inode->i_lock);
array = pnfs_add_commit_array(fl_cinfo, new, lseg);

View File

@ -663,7 +663,7 @@ nfs4_ff_layout_stat_io_start_read(struct inode *inode,
spin_unlock(&mirror->lock);
if (report)
pnfs_report_layoutstat(inode, GFP_KERNEL);
pnfs_report_layoutstat(inode, nfs_io_gfp_mask());
}
static void
@ -694,7 +694,7 @@ nfs4_ff_layout_stat_io_start_write(struct inode *inode,
spin_unlock(&mirror->lock);
if (report)
pnfs_report_layoutstat(inode, GFP_NOIO);
pnfs_report_layoutstat(inode, nfs_io_gfp_mask());
}
static void
@ -806,13 +806,10 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,
bool strict_iomode)
{
pnfs_put_lseg(pgio->pg_lseg);
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
nfs_req_openctx(req),
req_offset(req),
req->wb_bytes,
IOMODE_READ,
strict_iomode,
GFP_KERNEL);
pgio->pg_lseg =
pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req->wb_bytes, IOMODE_READ,
strict_iomode, nfs_io_gfp_mask());
if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL;
@ -894,13 +891,10 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
retry:
ff_layout_pg_check_layout(pgio, req);
if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
nfs_req_openctx(req),
req_offset(req),
req->wb_bytes,
IOMODE_RW,
false,
GFP_NOFS);
pgio->pg_lseg =
pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req->wb_bytes,
IOMODE_RW, false, nfs_io_gfp_mask());
if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL;
@ -953,13 +947,10 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req)
{
if (!pgio->pg_lseg) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
nfs_req_openctx(req),
req_offset(req),
req->wb_bytes,
IOMODE_RW,
false,
GFP_NOFS);
pgio->pg_lseg =
pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), req->wb_bytes,
IOMODE_RW, false, nfs_io_gfp_mask());
if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL;
@ -1258,7 +1249,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
mirror = FF_LAYOUT_COMP(lseg, idx);
err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, offset, length, status, opnum,
GFP_NOIO);
nfs_io_gfp_mask());
switch (status) {
case NFS4ERR_DELAY:
@ -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 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) {
spin_lock(&inode->i_lock);
array = pnfs_add_commit_array(fl_cinfo, new, lseg);
@ -2152,10 +2144,10 @@ ff_layout_prepare_layoutreturn(struct nfs4_layoutreturn_args *args)
struct nfs4_flexfile_layoutreturn_args *ff_args;
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)
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])
goto out_nomem_free;
@ -2192,8 +2184,8 @@ ff_layout_send_layouterror(struct pnfs_layout_segment *lseg)
if (list_empty(&head))
return;
errors = kmalloc_array(NFS42_LAYOUTERROR_MAX,
sizeof(*errors), GFP_NOFS);
errors = kmalloc_array(NFS42_LAYOUTERROR_MAX, sizeof(*errors),
nfs_io_gfp_mask());
if (errors != NULL) {
const struct nfs4_ff_layout_ds_err *pos;
size_t n = 0;
@ -2444,7 +2436,8 @@ ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args)
const int dev_count = PNFS_LAYOUTSTATS_MAXDEV;
/* 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)
return -ENOMEM;

View File

@ -80,6 +80,7 @@ enum nfs_param {
Opt_source,
Opt_tcp,
Opt_timeo,
Opt_trunkdiscovery,
Opt_udp,
Opt_v,
Opt_vers,
@ -180,6 +181,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
fsparam_string("source", Opt_source),
fsparam_flag ("tcp", Opt_tcp),
fsparam_u32 ("timeo", Opt_timeo),
fsparam_flag_no("trunkdiscovery", Opt_trunkdiscovery),
fsparam_flag ("udp", Opt_udp),
fsparam_flag ("v2", Opt_v),
fsparam_flag ("v3", Opt_v),
@ -529,6 +531,12 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
else
ctx->flags &= ~NFS_MOUNT_NOCTO;
break;
case Opt_trunkdiscovery:
if (result.negated)
ctx->flags &= ~NFS_MOUNT_TRUNK_DISCOVERY;
else
ctx->flags |= NFS_MOUNT_TRUNK_DISCOVERY;
break;
case Opt_ac:
if (result.negated)
ctx->flags |= NFS_MOUNT_NOAC;

View File

@ -19,8 +19,7 @@
#include "internal.h"
#include "iostat.h"
#include "fscache.h"
#define NFSDBG_FACILITY NFSDBG_FSCACHE
#include "nfstrace.h"
#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
vcookie = fscache_acquire_volume(key,
NULL, /* preferred_cache */
NULL, 0 /* coherency_data */);
dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
nfss, vcookie);
if (IS_ERR(vcookie)) {
if (vcookie != ERR_PTR(-EBUSY)) {
kfree(key);
@ -152,9 +149,6 @@ void nfs_fscache_release_super_cookie(struct super_block *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);
nfss->fscache = NULL;
kfree(nfss->fscache_uniq);
@ -173,7 +167,7 @@ void nfs_fscache_init_inode(struct inode *inode)
if (!(nfss->fscache && S_ISREG(inode->i_mode)))
return;
nfs_fscache_update_auxdata(&auxdata, nfsi);
nfs_fscache_update_auxdata(&auxdata, inode);
nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache,
0,
@ -181,7 +175,7 @@ void nfs_fscache_init_inode(struct inode *inode)
nfsi->fh.size,
&auxdata, /* aux_data */
sizeof(auxdata),
i_size_read(&nfsi->vfs_inode));
i_size_read(inode));
}
/*
@ -192,8 +186,6 @@ void nfs_fscache_clear_inode(struct inode *inode)
struct nfs_inode *nfsi = NFS_I(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);
nfsi->fscache = NULL;
}
@ -220,7 +212,6 @@ void nfs_fscache_clear_inode(struct inode *inode)
void nfs_fscache_open_file(struct inode *inode, struct file *filp)
{
struct nfs_fscache_inode_auxdata auxdata;
struct nfs_inode *nfsi = NFS_I(inode);
struct fscache_cookie *cookie = nfs_i_fscache(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)
fscache_use_cookie(cookie, open_for_write);
if (open_for_write) {
dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi);
nfs_fscache_update_auxdata(&auxdata, nfsi);
nfs_fscache_update_auxdata(&auxdata, inode);
fscache_invalidate(cookie, &auxdata, i_size_read(inode),
FSCACHE_INVAL_DIO_WRITE);
}
@ -240,11 +230,10 @@ EXPORT_SYMBOL_GPL(nfs_fscache_open_file);
void nfs_fscache_release_file(struct inode *inode, struct file *filp)
{
struct nfs_fscache_inode_auxdata auxdata;
struct nfs_inode *nfsi = NFS_I(inode);
struct fscache_cookie *cookie = nfs_i_fscache(inode);
if (fscache_cookie_valid(cookie)) {
nfs_fscache_update_auxdata(&auxdata, nfsi);
nfs_fscache_update_auxdata(&auxdata, inode);
fscache_unuse_cookie(cookie, &auxdata, NULL);
}
}
@ -319,58 +308,50 @@ static int fscache_fallback_write_page(struct inode *inode, struct page *page,
/*
* 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;
dfprintk(FSCACHE,
"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);
trace_nfs_fscache_read_page(inode, page);
if (PageChecked(page)) {
dfprintk(FSCACHE, "NFS: readpage_from_fscache: PageChecked\n");
ClearPageChecked(page);
return 1;
ret = 1;
goto out;
}
ret = fscache_fallback_read_page(inode, page);
if (ret < 0) {
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL);
dfprintk(FSCACHE,
"NFS: readpage_from_fscache failed %d\n", ret);
SetPageChecked(page);
return ret;
goto out;
}
/* Read completed synchronously */
dfprintk(FSCACHE, "NFS: readpage_from_fscache: read successful\n");
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK);
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
* 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;
dfprintk(FSCACHE,
"NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx))\n",
nfs_i_fscache(inode), page, page->index, page->flags);
trace_nfs_fscache_write_page(inode, page);
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) {
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL);
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED);
} else {
nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_OK);
}
trace_nfs_fscache_write_page_exit(inode, page, ret);
}

View File

@ -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_release_file(struct inode *, struct file *);
extern int __nfs_readpage_from_fscache(struct inode *, struct page *);
extern void __nfs_read_completion_to_fscache(struct nfs_pgio_header *hdr,
unsigned long bytes);
extern void __nfs_readpage_to_fscache(struct inode *, struct page *);
extern int __nfs_fscache_read_page(struct inode *, struct page *);
extern void __nfs_fscache_write_page(struct inode *, struct page *);
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.
*/
static inline int nfs_readpage_from_fscache(struct inode *inode,
struct page *page)
static inline int nfs_fscache_read_page(struct inode *inode, struct page *page)
{
if (NFS_I(inode)->fscache)
return __nfs_readpage_from_fscache(inode, page);
if (nfs_i_fscache(inode))
return __nfs_fscache_read_page(inode, page);
return -ENOBUFS;
}
@ -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
* 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)
{
if (NFS_I(inode)->fscache)
__nfs_readpage_to_fscache(inode, page);
if (nfs_i_fscache(inode))
__nfs_fscache_write_page(inode, page);
}
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));
auxdata->mtime_sec = nfsi->vfs_inode.i_mtime.tv_sec;
auxdata->mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
auxdata->ctime_sec = nfsi->vfs_inode.i_ctime.tv_sec;
auxdata->ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
auxdata->mtime_sec = inode->i_mtime.tv_sec;
auxdata->mtime_nsec = inode->i_mtime.tv_nsec;
auxdata->ctime_sec = inode->i_ctime.tv_sec;
auxdata->ctime_nsec = inode->i_ctime.tv_nsec;
if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
auxdata->change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
if (NFS_SERVER(inode)->nfs_client->rpc_ops->version == 4)
auxdata->change_attr = inode_peek_iversion_raw(inode);
}
/*
@ -107,9 +104,9 @@ static inline void nfs_fscache_invalidate(struct inode *inode, int flags)
struct nfs_inode *nfsi = NFS_I(inode);
if (nfsi->fscache) {
nfs_fscache_update_auxdata(&auxdata, nfsi);
nfs_fscache_update_auxdata(&auxdata, inode);
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)
{
return 1; /* True: may release page */
}
static inline int nfs_readpage_from_fscache(struct inode *inode,
struct page *page)
static inline int nfs_fscache_read_page(struct inode *inode, struct page *page)
{
return -ENOBUFS;
}
static inline void nfs_readpage_to_fscache(struct inode *inode,
struct page *page) {}
static inline void nfs_fscache_write_page(struct inode *inode, struct page *page) {}
static inline void nfs_fscache_invalidate(struct inode *inode, int flags) {}
static inline const char *nfs_server_fscache_state(struct nfs_server *server)

View File

@ -203,14 +203,13 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
NFS_INO_INVALID_OTHER |
NFS_INO_INVALID_XATTR);
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))
flags &= ~NFS_INO_INVALID_XATTR;
if (flags & NFS_INO_INVALID_DATA)
nfs_fscache_invalidate(inode, 0);
flags &= ~(NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED);
flags &= ~NFS_INO_REVAL_FORCED;
nfsi->cache_validity |= flags;
@ -236,19 +235,17 @@ static void nfs_zap_caches_locked(struct inode *inode)
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = jiffies;
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_DATA
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_INVALID_XATTR
| NFS_INO_REVAL_PAGECACHE);
} else
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_INVALID_XATTR
| NFS_INO_REVAL_PAGECACHE);
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR |
NFS_INO_INVALID_DATA |
NFS_INO_INVALID_ACCESS |
NFS_INO_INVALID_ACL |
NFS_INO_INVALID_XATTR);
else
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR |
NFS_INO_INVALID_ACCESS |
NFS_INO_INVALID_ACL |
NFS_INO_INVALID_XATTR);
nfs_zap_label_cache_locked(nfsi);
}
@ -564,8 +561,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
inode->i_gid = fattr->gid;
else if (fattr_supported & NFS_ATTR_FATTR_GROUP)
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)
inode->i_blocks = fattr->du.nfs2.blocks;
else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED &&
@ -785,26 +780,32 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
}
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
/*
* 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)
{
return nfs_server_capable(inode, NFS_CAP_READDIRPLUS) &&
!nfs_have_writebacks(inode) && NFS_MAXATTRTIMEO(inode) > 5 * HZ;
}
static void nfs_readdirplus_parent_cache_miss(struct dentry *dentry)
{
struct dentry *parent;
if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS))
return;
parent = dget_parent(dentry);
nfs_force_use_readdirplus(d_inode(parent));
dput(parent);
if (!IS_ROOT(dentry)) {
struct dentry *parent = dget_parent(dentry);
nfs_readdir_record_entry_cache_miss(d_inode(parent));
dput(parent);
}
}
static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
{
struct dentry *parent;
if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS))
return;
parent = dget_parent(dentry);
nfs_advise_use_readdirplus(d_inode(parent));
dput(parent);
if (!IS_ROOT(dentry)) {
struct dentry *parent = dget_parent(dentry);
nfs_readdir_record_entry_cache_hit(d_inode(parent));
dput(parent);
}
}
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,
int err = 0;
bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
bool do_update = false;
bool readdirplus_enabled = nfs_getattr_readdirplus_enable(inode);
trace_nfs_getattr_enter(inode);
@ -848,7 +850,8 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
STATX_INO | STATX_SIZE | STATX_BLOCKS;
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
nfs_readdirplus_parent_cache_hit(path->dentry);
if (readdirplus_enabled)
nfs_readdirplus_parent_cache_hit(path->dentry);
goto out_no_revalidate;
}
@ -898,15 +901,12 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
if (do_update) {
/* Update the attribute cache */
if (!(server->flags & NFS_MOUNT_NOAC))
if (readdirplus_enabled)
nfs_readdirplus_parent_cache_miss(path->dentry);
else
nfs_readdirplus_parent_cache_hit(path->dentry);
err = __nfs_revalidate_inode(server, inode);
if (err)
goto out;
} else
} else if (readdirplus_enabled)
nfs_readdirplus_parent_cache_hit(path->dentry);
out_no_revalidate:
/* Only return attributes that were revalidated. */
@ -952,7 +952,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
res = __nfs_find_lock_context(ctx);
rcu_read_unlock();
if (res == NULL) {
new = kmalloc(sizeof(*new), GFP_KERNEL);
new = kmalloc(sizeof(*new), GFP_KERNEL_ACCOUNT);
if (new == NULL)
return ERR_PTR(-ENOMEM);
nfs_init_lock_context(new);
@ -1030,7 +1030,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
{
struct nfs_open_context *ctx;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
if (!ctx)
return ERR_PTR(-ENOMEM);
nfs_sb_active(dentry->d_sb);
@ -1583,7 +1583,7 @@ struct nfs_fattr *nfs_alloc_fattr(void)
{
struct nfs_fattr *fattr;
fattr = kmalloc(sizeof(*fattr), GFP_NOFS);
fattr = kmalloc(sizeof(*fattr), GFP_KERNEL);
if (fattr != NULL) {
nfs_fattr_init(fattr);
fattr->label = NULL;
@ -1599,7 +1599,7 @@ struct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server)
if (!fattr)
return NULL;
fattr->label = nfs4_label_alloc(server, GFP_NOFS);
fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
if (IS_ERR(fattr->label)) {
kfree(fattr);
return NULL;
@ -1613,7 +1613,7 @@ struct nfs_fh *nfs_alloc_fhandle(void)
{
struct nfs_fh *fh;
fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS);
fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
if (fh != NULL)
fh->size = 0;
return fh;

View File

@ -366,8 +366,8 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
const struct nfs_client_initdata *);
/* dir.c */
extern void nfs_advise_use_readdirplus(struct inode *dir);
extern void nfs_force_use_readdirplus(struct inode *dir);
extern void nfs_readdir_record_entry_cache_hit(struct inode *dir);
extern void nfs_readdir_record_entry_cache_miss(struct inode *dir);
extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
struct shrink_control *sc);
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,
int nfs_rename(struct user_namespace *, struct inode *, struct dentry *,
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 */
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);
@ -573,6 +587,13 @@ nfs_write_match_verf(const struct nfs_writeverf *verf,
!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 */
extern struct rpc_task *
nfs_async_rename(struct inode *old_dir, struct inode *new_dir,

View File

@ -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);
if (unlikely(error))
return error;
return -EAGAIN;
/*
* The type (size and byte order) of nfscookie isn't defined in
* RFC 1094. This implementation assumes that it's an XDR uint32.
*/
entry->prev_cookie = entry->cookie;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
return -EAGAIN;

View File

@ -1261,6 +1261,8 @@ static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
static void encode_readdirplus3args(struct xdr_stream *xdr,
const struct nfs3_readdirargs *args)
{
uint32_t dircount = args->count;
uint32_t maxcount = args->count;
__be32 *p;
encode_nfs_fh3(xdr, args->fh);
@ -1273,9 +1275,8 @@ static void encode_readdirplus3args(struct xdr_stream *xdr,
* readdirplus: need dircount + buffer size.
* We just make sure we make dircount big enough
*/
*p++ = cpu_to_be32(args->count >> 3);
*p = cpu_to_be32(args->count);
*p++ = cpu_to_be32(dircount);
*p = cpu_to_be32(maxcount);
}
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,
bool plus)
{
struct user_namespace *userns = rpc_userns(entry->server->client);
struct nfs_entry old = *entry;
__be32 *p;
int error;
u64 new_cookie;
@ -1987,15 +1987,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
error = decode_fileid3(xdr, &entry->ino);
if (unlikely(error))
return error;
return -EAGAIN;
error = decode_inline_filename3(xdr, &entry->name, &entry->len);
if (unlikely(error))
return error;
return -EAGAIN;
error = decode_cookie3(xdr, &new_cookie);
if (unlikely(error))
return error;
return -EAGAIN;
entry->d_type = DT_UNKNOWN;
@ -2003,7 +2003,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
entry->fattr->valid = 0;
error = decode_post_op_attr(xdr, entry->fattr, userns);
if (unlikely(error))
return error;
return -EAGAIN;
if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
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,
return -EAGAIN;
if (*p != xdr_zero) {
error = decode_nfs_fh3(xdr, entry->fh);
if (unlikely(error)) {
if (error == -E2BIG)
goto out_truncated;
return error;
}
if (unlikely(error))
return -EAGAIN;
} else
zero_nfs_fh3(entry->fh);
}
entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie;
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,
/* ignore properties */
result->lease_time = 0;
result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
result->xattr_support = 0;
return 0;
}

View File

@ -175,28 +175,27 @@ static int handle_async_copy(struct nfs42_copy_res *res,
nfs4_stateid *src_stateid,
bool *restart)
{
struct nfs4_copy_state *copy, *tmp_copy;
struct nfs4_copy_state *copy, *tmp_copy = NULL, *iter;
int status = NFS4_OK;
bool found_pending = false;
struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
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)
return -ENOMEM;
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,
copies) {
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
if (memcmp(&res->write_res.stateid, &iter->stateid,
NFS4_STATEID_SIZE))
continue;
found_pending = true;
list_del(&tmp_copy->copies);
tmp_copy = iter;
list_del(&iter->copies);
break;
}
if (found_pending) {
if (tmp_copy) {
spin_unlock(&dst_server->nfs_client->cl_lock);
kfree(copy);
copy = tmp_copy;
@ -254,7 +253,7 @@ static int process_copy_commit(struct file *dst, loff_t pos_dst,
struct nfs_commitres cres;
int status = -ENOMEM;
cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_KERNEL);
if (!cres.verf)
goto out;
@ -357,7 +356,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
res->commit_res.verf = NULL;
if (args->sync) {
res->commit_res.verf =
kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
kzalloc(sizeof(struct nfs_writeverf), GFP_KERNEL);
if (!res->commit_res.verf)
return -ENOMEM;
}
@ -552,7 +551,7 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL))
return -EOPNOTSUPP;
data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS);
data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
@ -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));
l_ctx = nfs_get_lock_context(ctx);
if (IS_ERR(l_ctx))
return PTR_ERR(l_ctx);
if (IS_ERR(l_ctx)) {
status = PTR_ERR(l_ctx);
goto out;
}
status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
FMODE_READ);
@ -600,7 +601,7 @@ static int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
if (status) {
if (status == -EAGAIN)
status = -NFS4ERR_BAD_STATEID;
return status;
goto out;
}
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,
if (status == -ENOTSUPP)
src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
out:
put_nfs_open_context(nfs_file_open_context(src));
return status;
}
@ -626,7 +628,7 @@ int nfs42_proc_copy_notify(struct file *src, struct file *dst,
if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
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)
return -ENOMEM;
@ -1014,7 +1016,7 @@ int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
return -EOPNOTSUPP;
if (n > NFS42_LAYOUTERROR_MAX)
return -EINVAL;
data = nfs42_alloc_layouterror_data(lseg, GFP_NOFS);
data = nfs42_alloc_layouterror_data(lseg, nfs_io_gfp_mask());
if (!data)
return -ENOMEM;
for (i = 0; i < n; i++) {

View File

@ -199,7 +199,7 @@ nfs4_xattr_alloc_entry(const char *name, const void *value,
flags = NFS4_XATTR_ENTRY_EXTVAL;
}
buf = kmalloc(alloclen, GFP_KERNEL_ACCOUNT | GFP_NOFS);
buf = kmalloc(alloclen, GFP_KERNEL);
if (buf == NULL)
return NULL;
entry = (struct nfs4_xattr_entry *)buf;
@ -213,7 +213,7 @@ nfs4_xattr_alloc_entry(const char *name, const void *value,
if (flags & NFS4_XATTR_ENTRY_EXTVAL) {
valp = kvmalloc(len, GFP_KERNEL_ACCOUNT | GFP_NOFS);
valp = kvmalloc(len, GFP_KERNEL);
if (valp == NULL) {
kfree(buf);
return NULL;
@ -289,8 +289,7 @@ nfs4_xattr_alloc_cache(void)
{
struct nfs4_xattr_cache *cache;
cache = kmem_cache_alloc(nfs4_xattr_cache_cachep,
GFP_KERNEL_ACCOUNT | GFP_NOFS);
cache = kmem_cache_alloc(nfs4_xattr_cache_cachep, GFP_KERNEL);
if (cache == NULL)
return NULL;

View File

@ -42,6 +42,7 @@ enum nfs4_client_state {
NFS4CLNT_LEASE_MOVED,
NFS4CLNT_DELEGATION_EXPIRED,
NFS4CLNT_RUN_MANAGER,
NFS4CLNT_MANAGER_AVAILABLE,
NFS4CLNT_RECALL_RUNNING,
NFS4CLNT_RECALL_ANY_LAYOUT_READ,
NFS4CLNT_RECALL_ANY_LAYOUT_RW,

View File

@ -165,7 +165,7 @@ retry:
if (sync)
return -EOPNOTSUPP;
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
GFP_NOFS);
GFP_KERNEL);
if (unlikely(cn_resp == NULL))
return -ENOMEM;
@ -180,8 +180,8 @@ retry:
ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count,
nss, cnrs, sync);
out:
if (!nfs42_files_from_same_server(file_in, file_out))
kfree(cn_resp);
kfree(cn_resp);
if (ret == -EAGAIN)
goto retry;
return ret;
@ -339,7 +339,7 @@ static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
res = ERR_PTR(-ENOMEM);
len = strlen(SSC_READ_NAME_BODY) + 16;
read_name = kzalloc(len, GFP_NOFS);
read_name = kzalloc(len, GFP_KERNEL);
if (read_name == NULL)
goto out;
snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);

View File

@ -1392,13 +1392,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
case NFS4_OPEN_CLAIM_FH:
p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE |
NFS4_ACCESS_EXECUTE;
#ifdef CONFIG_NFS_V4_2
if (!(server->caps & NFS_CAP_XATTR))
break;
p->o_arg.access |= NFS4_ACCESS_XAREAD | NFS4_ACCESS_XAWRITE |
NFS4_ACCESS_XALIST;
#endif
NFS4_ACCESS_EXECUTE |
nfs_access_xattr_mask(server);
}
p->o_arg.clientid = server->nfs_client->cl_clientid;
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,
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK)
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;
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
buflen = server->rsize;
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)
return -ENOMEM;
@ -6609,7 +6606,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
};
int status = 0;
data = kzalloc(sizeof(*data), GFP_NOFS);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
@ -6797,7 +6794,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
struct nfs4_state *state = lsp->ls_state;
struct inode *inode = state->inode;
p = kzalloc(sizeof(*p), GFP_NOFS);
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL)
return NULL;
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
task_setup_data.flags |= RPC_TASK_MOVEABLE;
data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
fl->fl_u.nfs4_fl.owner,
recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
fl->fl_u.nfs4_fl.owner, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
if (IS_SETLKW(cmd))
@ -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)
return;
data = kmalloc(sizeof(*data), GFP_NOFS);
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return;
data->lsp = lsp;
@ -8012,6 +8008,18 @@ static int _nfs41_proc_get_locations(struct nfs_server *server,
.rpc_resp = &res,
.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;
nfs_fattr_init(&locations->fattr);
@ -8019,8 +8027,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server,
locations->nlocations = 0;
nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
status = nfs4_call_sync_sequence(clnt, server, &msg,
&args.seq_args, &res.seq_res);
status = nfs4_call_sync_custom(&task_setup_data);
if (status == NFS4_OK &&
res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
status = -NFS4ERR_LEASE_MOVED;
@ -8333,6 +8340,7 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
case -NFS4ERR_DEADSESSION:
nfs4_schedule_session_recovery(clp->cl_session,
task->tk_status);
return;
}
if (args->dir == NFS4_CDFC4_FORE_OR_BOTH &&
res->dir != NFS4_CDFS4_BOTH) {
@ -9291,7 +9299,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
goto out_err;
ret = ERR_PTR(-ENOMEM);
calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
if (calldata == NULL)
goto out_put_clp;
nfs4_init_sequence(&calldata->args, &calldata->res, 0, is_privileged);
@ -10222,7 +10230,7 @@ static int nfs41_free_stateid(struct nfs_server *server,
&task_setup.rpc_client, &msg);
dprintk("NFS call free_stateid %p\n", stateid);
data = kmalloc(sizeof(*data), GFP_NOFS);
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->server = server;
@ -10461,6 +10469,24 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
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 = {
.create = nfs_create,
.lookup = nfs_lookup,
@ -10538,6 +10564,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.create_server = nfs4_create_server,
.clone_server = nfs_clone_server,
.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 = {

View File

@ -49,6 +49,7 @@
#include <linux/workqueue.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/sched/mm.h>
#include <linux/sunrpc/clnt.h>
@ -666,7 +667,7 @@ nfs4_alloc_open_state(void)
{
struct nfs4_state *state;
state = kzalloc(sizeof(*state), GFP_NOFS);
state = kzalloc(sizeof(*state), GFP_KERNEL_ACCOUNT);
if (!state)
return NULL;
refcount_set(&state->count, 1);
@ -820,7 +821,7 @@ static void __nfs4_close(struct nfs4_state *state,
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)
@ -869,14 +870,15 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
struct nfs4_lock_state *lsp;
struct nfs_server *server = state->owner->so_server;
lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
lsp = kzalloc(sizeof(*lsp), GFP_KERNEL_ACCOUNT);
if (lsp == NULL)
return NULL;
nfs4_init_seqid_counter(&lsp->ls_seqid);
refcount_set(&lsp->ls_count, 1);
lsp->ls_state = state;
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)
goto out_free;
INIT_LIST_HEAD(&lsp->ls_locks);
@ -1205,10 +1207,17 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
{
struct task_struct *task;
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);
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;
}
set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
__module_get(THIS_MODULE);
refcount_inc(&clp->cl_count);
@ -1224,6 +1233,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
printk(KERN_ERR "%s: kthread_run: %ld\n",
__func__, PTR_ERR(task));
nfs4_clear_state_manager_bit(clp);
clear_bit(NFS4CLNT_MANAGER_AVAILABLE, &clp->cl_state);
nfs_put_client(clp);
module_put(THIS_MODULE);
}
@ -2560,9 +2570,17 @@ static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
static void nfs4_state_manager(struct nfs_client *clp)
{
unsigned int memflags;
int status = 0;
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 */
do {
trace_nfs4_state_mgr(clp);
@ -2657,6 +2675,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
}
memalloc_nofs_restore(memflags);
nfs4_end_drain_session(clp);
nfs4_clear_state_manager_bit(clp);
@ -2669,11 +2688,8 @@ static void nfs4_state_manager(struct nfs_client *clp)
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());
goto out_drain;
@ -2686,6 +2702,7 @@ out_error:
clp->cl_hostname, -status);
ssleep(1);
out_drain:
memalloc_nofs_restore(memflags);
nfs4_end_drain_session(clp);
nfs4_clear_state_manager_bit(clp);
}
@ -2693,9 +2710,31 @@ out_drain:
static int nfs4_run_state_manager(void *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);
again:
set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
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);
return 0;
}

View File

@ -1605,7 +1605,8 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
FATTR4_WORD0_RDATTR_ERROR,
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];
uint32_t attrlen = 0;
unsigned int i;
@ -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_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
dircount >>= 1;
}
/* Use mounted_on_fileid only if the server supports it */
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
encode_nfs4_verifier(xdr, &readdir->verifier);
p = reserve_space(xdr, 12 + (attrlen << 2));
*p++ = cpu_to_be32(dircount);
*p++ = cpu_to_be32(readdir->count);
*p++ = cpu_to_be32(maxcount);
*p++ = cpu_to_be32(attrlen);
for (i = 0; i < attrlen; i++)
*p++ = cpu_to_be32(attrs[i]);
@ -7508,7 +7508,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie;
return 0;

View File

@ -21,7 +21,6 @@
{ NFS_INO_INVALID_ATIME, "INVALID_ATIME" }, \
{ NFS_INO_INVALID_ACCESS, "INVALID_ACCESS" }, \
{ NFS_INO_INVALID_ACL, "INVALID_ACL" }, \
{ NFS_INO_REVAL_PAGECACHE, "REVAL_PAGECACHE" }, \
{ NFS_INO_REVAL_FORCED, "REVAL_FORCED" }, \
{ NFS_INO_INVALID_LABEL, "INVALID_LABEL" }, \
{ NFS_INO_INVALID_CHANGE, "INVALID_CHANGE" }, \
@ -37,7 +36,6 @@
#define nfs_show_nfsi_flags(v) \
__print_flags(v, "|", \
{ BIT(NFS_INO_ADVISE_RDPLUS), "ADVISE_RDPLUS" }, \
{ BIT(NFS_INO_STALE), "STALE" }, \
{ BIT(NFS_INO_ACL_LRU_SET), "ACL_LRU_SET" }, \
{ BIT(NFS_INO_INVALIDATING), "INVALIDATING" }, \
@ -162,6 +160,9 @@ DEFINE_NFS_INODE_EVENT(nfs_fsync_enter);
DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit);
DEFINE_NFS_INODE_EVENT(nfs_access_enter);
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,
TP_PROTO(
@ -273,6 +274,122 @@ DEFINE_NFS_UPDATE_SIZE_EVENT(wcc);
DEFINE_NFS_UPDATE_SIZE_EVENT(update);
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,
TP_PROTO(
const struct inode *dir,
@ -366,6 +483,9 @@ DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_enter);
DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_exit);
DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_revalidate_enter);
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,
TP_PROTO(
@ -889,11 +1009,11 @@ TRACE_EVENT(nfs_aop_readpage_done,
TRACE_EVENT(nfs_aop_readahead,
TP_PROTO(
const struct inode *inode,
struct page *page,
loff_t pos,
unsigned int nr_pages
),
TP_ARGS(inode, page, nr_pages),
TP_ARGS(inode, pos, nr_pages),
TP_STRUCT__entry(
__field(dev_t, dev)
@ -911,7 +1031,7 @@ TRACE_EVENT(nfs_aop_readahead,
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->version = inode_peek_iversion_raw(inode);
__entry->offset = page_index(page) << PAGE_SHIFT;
__entry->offset = pos;
__entry->nr_pages = nr_pages;
),
@ -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,
TP_PROTO(
const struct nfs_pgio_header *hdr,

View File

@ -90,10 +90,10 @@ void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos)
}
}
static inline struct nfs_page *
nfs_page_alloc(void)
static inline struct nfs_page *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)
INIT_LIST_HEAD(&p->wb_list);
return p;
@ -892,7 +892,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
struct nfs_commit_info cinfo;
struct nfs_page_array *pg_array = &hdr->page_array;
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);
pg_array->npages = pagecount;
@ -979,7 +979,7 @@ nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc,
desc->pg_mirrors_dynamic = NULL;
if (mirror_count == 1)
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) {
for (i = 0; i < mirror_count; i++)
nfs_pageio_mirror_init(&ret[i], desc->pg_bsize);
@ -1218,6 +1218,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
do {
list_splice_init(&mirror->pg_list, &head);
mirror->pg_recoalesce = 0;
while (!list_empty(&head)) {
struct nfs_page *req;

View File

@ -92,6 +92,17 @@ find_pnfs_driver(u32 id)
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
unset_pnfs_layoutdriver(struct nfs_server *nfss)
{
@ -1233,7 +1244,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo,
int status = 0;
*pcred = NULL;
lrp = kzalloc(sizeof(*lrp), GFP_NOFS);
lrp = kzalloc(sizeof(*lrp), nfs_io_gfp_mask());
if (unlikely(lrp == NULL)) {
status = -ENOMEM;
spin_lock(&ino->i_lock);
@ -2206,7 +2217,7 @@ _pnfs_grab_empty_layout(struct inode *ino, struct nfs_open_context *ctx)
struct pnfs_layout_hdr *lo;
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)
goto out_unlock;
if (!test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))
@ -2249,8 +2260,8 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data,
lo = _pnfs_grab_empty_layout(ino, ctx);
if (!lo)
return;
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid,
&rng, GFP_KERNEL);
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid, &rng,
nfs_io_gfp_mask());
if (!lgp) {
pnfs_clear_first_layoutget(lo);
nfs_layoutget_end(lo);
@ -2275,8 +2286,8 @@ static void _lgopen_prepare_floating(struct nfs4_opendata *data,
};
struct nfs4_layoutget *lgp;
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid,
&rng, GFP_KERNEL);
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, &current_stateid, &rng,
nfs_io_gfp_mask());
if (!lgp)
return;
data->lgp = lgp;
@ -2691,13 +2702,11 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
else
rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
nfs_req_openctx(req),
req_offset(req),
rd_size,
IOMODE_READ,
false,
GFP_KERNEL);
pgio->pg_lseg =
pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), rd_size,
IOMODE_READ, false,
nfs_io_gfp_mask());
if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL;
@ -2718,13 +2727,10 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
pnfs_generic_pg_check_layout(pgio);
pnfs_generic_pg_check_range(pgio, req);
if (pgio->pg_lseg == NULL) {
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
nfs_req_openctx(req),
req_offset(req),
wb_size,
IOMODE_RW,
false,
GFP_KERNEL);
pgio->pg_lseg =
pnfs_update_layout(pgio->pg_inode, nfs_req_openctx(req),
req_offset(req), wb_size, IOMODE_RW,
false, nfs_io_gfp_mask());
if (IS_ERR(pgio->pg_lseg)) {
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
pgio->pg_lseg = NULL;
@ -3183,7 +3189,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
status = -ENOMEM;
/* 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)
goto clear_layoutcommitting;
@ -3250,7 +3256,7 @@ struct nfs4_threshold *pnfs_mdsthreshold_alloc(void)
{
struct nfs4_threshold *thp;
thp = kzalloc(sizeof(*thp), GFP_NOFS);
thp = kzalloc(sizeof(*thp), nfs_io_gfp_mask());
if (!thp) {
dprintk("%s mdsthreshold allocation failed\n", __func__);
return NULL;

View File

@ -234,6 +234,8 @@ struct pnfs_devicelist {
extern int pnfs_register_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 */
extern size_t max_response_pages(struct nfs_server *server);

View File

@ -419,7 +419,7 @@ static struct nfs_commit_data *
pnfs_bucket_fetch_commitdata(struct pnfs_commit_bucket *bucket,
struct nfs_commit_info *cinfo)
{
struct nfs_commit_data *data = nfs_commitdata_alloc(false);
struct nfs_commit_data *data = nfs_commitdata_alloc();
if (!data)
return NULL;
@ -515,7 +515,11 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
unsigned int nreq = 0;
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;
list_splice_init(mds_pages, &data->pages);
list_add_tail(&data->list, &list);

View File

@ -92,6 +92,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
info->maxfilesize = 0x7FFFFFFF;
info->lease_time = 0;
info->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
info->xattr_support = 0;
return 0;
}

View File

@ -123,7 +123,7 @@ static void nfs_readpage_release(struct nfs_page *req, int error)
struct address_space *mapping = page_file_mapping(page);
if (PageUptodate(page))
nfs_readpage_to_fscache(inode, page);
nfs_fscache_write_page(inode, page);
else if (!PageError(page) && !PagePrivate(page))
generic_error_remove_page(mapping, page);
unlock_page(page);
@ -194,10 +194,6 @@ static void nfs_initiate_read(struct nfs_pgio_header *hdr,
const struct nfs_rpc_ops *rpc_ops,
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);
trace_nfs_initiate_read(hdr);
}
@ -290,9 +286,8 @@ static void nfs_readpage_result(struct rpc_task *task,
}
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;
unsigned int rsize = NFS_SERVER(inode)->rsize;
struct nfs_page *new;
@ -306,7 +301,7 @@ readpage_async_filler(void *data, struct page *page)
aligned_len = min_t(unsigned int, ALIGN(len, rsize), PAGE_SIZE);
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)
goto out_unlock;
}
@ -397,14 +392,16 @@ out_unlock:
return ret;
}
int nfs_readpages(struct file *file, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
void nfs_readahead(struct readahead_control *ractl)
{
unsigned int nr_pages = readahead_count(ractl);
struct file *file = ractl->file;
struct nfs_readdesc desc;
struct inode *inode = mapping->host;
struct inode *inode = ractl->mapping->host;
struct page *page;
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);
ret = -ESTALE;
@ -422,14 +419,18 @@ int nfs_readpages(struct file *file, struct address_space *mapping,
nfs_pageio_init_read(&desc.pgio, inode, false,
&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);
put_nfs_open_context(desc.ctx);
out:
trace_nfs_aop_readahead_done(inode, nr_pages, ret);
return ret;
}
int __init nfs_init_readpagecache(void)

View File

@ -70,27 +70,17 @@ static mempool_t *nfs_wdata_mempool;
static struct kmem_cache *nfs_cdata_cachep;
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;
if (never_fail)
p = mempool_alloc(nfs_commit_mempool, GFP_NOIO);
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 = kmem_cache_zalloc(nfs_cdata_cachep, nfs_io_gfp_mask());
if (!p) {
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)
return NULL;
memset(p, 0, sizeof(*p));
}
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
return p;
}
@ -104,9 +94,15 @@ EXPORT_SYMBOL_GPL(nfs_commit_free);
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;
memset(p, 0, sizeof(*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));
}
p->rw_mode = FMODE_WRITE;
return p;
}
@ -306,7 +302,7 @@ static void nfs_set_pageerror(struct address_space *mapping)
/* Force file size revalidation */
spin_lock(&inode->i_lock);
nfs_set_cache_invalid(inode, NFS_INO_REVAL_FORCED |
NFS_INO_REVAL_PAGECACHE |
NFS_INO_INVALID_CHANGE |
NFS_INO_INVALID_SIZE);
spin_unlock(&inode->i_lock);
}
@ -316,7 +312,10 @@ static void nfs_mapping_set_error(struct page *page, int error)
struct address_space *mapping = page_file_mapping(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);
}
@ -1417,6 +1416,8 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr,
{
int priority = flush_task_priority(how);
if (IS_SWAPFILE(hdr->inode))
task_setup_data->flags |= RPC_TASK_SWAPPER;
task_setup_data->priority = priority;
rpc_ops->write_setup(hdr, msg, &task_setup_data->rpc_client);
trace_nfs_initiate_write(hdr);
@ -1829,7 +1830,11 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
if (list_empty(head))
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 */
nfs_init_commit(data, head, NULL, cinfo);

View File

@ -45,11 +45,6 @@
*/
#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
*/
@ -101,13 +96,17 @@ struct nfs_open_context {
struct nfs_open_dir_context {
struct list_head list;
atomic_t cache_hits;
atomic_t cache_misses;
unsigned long attr_gencount;
__be32 verf[NFS_DIR_VERIFIER_SIZE];
__u64 dir_cookie;
__u64 dup_cookie;
__u64 last_cookie;
pgoff_t page_index;
signed char duped;
unsigned int dtsize;
bool force_clear;
bool eof;
struct rcu_head rcu_head;
};
/*
@ -247,7 +246,6 @@ struct nfs4_copy_state {
#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_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_INVALID_LABEL BIT(7) /* cached label is invalid */
#define NFS_INO_INVALID_CHANGE BIT(8) /* cached change is invalid */
@ -273,12 +271,11 @@ struct nfs4_copy_state {
/*
* Bit offsets in flags field
*/
#define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */
#define NFS_INO_STALE (1) /* possible stale inode */
#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_PRESERVE_UNLINKED (4) /* preserve file if removed while open */
#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_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
@ -355,17 +352,15 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&inode->i_lock);
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_INVALID_CHANGE
| NFS_INO_INVALID_CTIME;
nfsi->cache_validity |= NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
NFS_INO_INVALID_SIZE;
if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
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;
}
@ -513,10 +508,10 @@ static inline const struct cred *nfs_file_cred(struct file *file)
* linux/fs/nfs/direct.c
*/
extern ssize_t nfs_direct_IO(struct kiocb *, struct iov_iter *);
extern ssize_t nfs_file_direct_read(struct kiocb *iocb,
struct iov_iter *iter);
extern ssize_t nfs_file_direct_write(struct kiocb *iocb,
struct iov_iter *iter);
ssize_t nfs_file_direct_read(struct kiocb *iocb,
struct iov_iter *iter, bool swap);
ssize_t nfs_file_direct_write(struct kiocb *iocb,
struct iov_iter *iter, bool swap);
/*
* linux/fs/nfs/dir.c
@ -585,24 +580,22 @@ extern int nfs_wb_all(struct inode *inode);
extern int nfs_wb_page(struct inode *inode, struct page *page);
int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio);
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);
bool nfs_commit_end(struct nfs_mds_commit_info *cinfo);
static inline int
nfs_have_writebacks(struct inode *inode)
static inline bool nfs_have_writebacks(const struct inode *inode)
{
if (S_ISREG(inode->i_mode))
return atomic_long_read(&NFS_I(inode)->nrequests) != 0;
return 0;
return false;
}
/*
* linux/fs/nfs/read.c
*/
extern int nfs_readpage(struct file *, struct page *);
extern int nfs_readpages(struct file *, struct address_space *,
struct list_head *, unsigned);
void nfs_readahead(struct readahead_control *);
/*
* inline functions

View File

@ -152,6 +152,7 @@ struct nfs_server {
#define NFS_MOUNT_SOFTREVAL 0x800000
#define NFS_MOUNT_WRITE_EAGER 0x01000000
#define NFS_MOUNT_WRITE_WAIT 0x02000000
#define NFS_MOUNT_TRUNK_DISCOVERY 0x04000000
unsigned int fattr_valid; /* Valid attributes */
unsigned int caps; /* server capabilities */

View File

@ -745,8 +745,7 @@ struct nfs_auth_info {
*/
struct nfs_entry {
__u64 ino;
__u64 cookie,
prev_cookie;
__u64 cookie;
const char * name;
unsigned int len;
int eof;
@ -1798,6 +1797,8 @@ struct nfs_rpc_ops {
struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *, rpc_authflavor_t);
int (*discover_trunking)(struct nfs_server *, struct nfs_fh *);
void (*enable_swap)(struct inode *inode);
void (*disable_swap)(struct inode *inode);
};
/*

View File

@ -99,6 +99,7 @@ struct rpc_auth_create_args {
/* Flags for rpcauth_lookupcred() */
#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
#define RPCAUTH_LOOKUP_ASYNC 0x02 /* Don't block waiting for memory */
/*
* Client authentication ops

View File

@ -124,7 +124,6 @@ struct rpc_task_setup {
#define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */
#define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */
#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_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
@ -263,6 +262,7 @@ void rpc_destroy_mempool(void);
extern struct workqueue_struct *rpciod_workqueue;
extern struct workqueue_struct *xprtiod_workqueue;
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)
{

View File

@ -139,6 +139,9 @@ struct rpc_xprt_ops {
void (*rpcbind)(struct rpc_task *task);
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
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);
void (*buf_free)(struct rpc_task *task);
void (*prepare_request)(struct rpc_rqst *req);

View File

@ -10,7 +10,6 @@
int init_socket_xprt(void);
void cleanup_socket_xprt(void);
unsigned short get_srcport(struct rpc_xprt *);
#define RPC_MIN_RESVPORT (1U)
#define RPC_MAX_RESVPORT (65535U)
@ -89,5 +88,7 @@ struct sock_xprt {
#define XPRT_SOCK_WAKE_WRITE (5)
#define XPRT_SOCK_WAKE_PENDING (6)
#define XPRT_SOCK_WAKE_DISCONNECT (7)
#define XPRT_SOCK_CONNECT_SENT (8)
#define XPRT_SOCK_NOSPACE (9)
#endif /* _LINUX_SUNRPC_XPRTSOCK_H */

View File

@ -311,7 +311,6 @@ TRACE_EVENT(rpc_request,
{ RPC_TASK_MOVEABLE, "MOVEABLE" }, \
{ RPC_TASK_NULLCREDS, "NULLCREDS" }, \
{ RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \
{ RPC_TASK_ROOTCREDS, "ROOTCREDS" }, \
{ RPC_TASK_DYNAMIC, "DYNAMIC" }, \
{ RPC_TASK_NO_ROUND_ROBIN, "NO_ROUND_ROBIN" }, \
{ RPC_TASK_SOFT, "SOFT" }, \

View File

@ -45,6 +45,7 @@
#define NFS4_OPEN_RESULT_CONFIRM 0x0002
#define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004
#define NFS4_OPEN_RESULT_PRESERVE_UNLINKED 0x0008
#define NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK 0x0020
#define NFS4_SHARE_ACCESS_MASK 0x000F

View File

@ -52,7 +52,7 @@
#define NFSDBG_CALLBACK 0x0100
#define NFSDBG_CLIENT 0x0200
#define NFSDBG_MOUNT 0x0400
#define NFSDBG_FSCACHE 0x0800
#define NFSDBG_FSCACHE 0x0800 /* unused */
#define NFSDBG_PNFS 0x1000
#define NFSDBG_PNFS_LD 0x2000
#define NFSDBG_STATE 0x4000

View File

@ -615,6 +615,8 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
};
struct rpc_cred *ret;
if (RPC_IS_ASYNC(task))
lookupflags |= RPCAUTH_LOOKUP_ASYNC;
ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
put_cred(acred.cred);
return ret;
@ -631,6 +633,8 @@ rpcauth_bind_machine_cred(struct rpc_task *task, int lookupflags)
if (!acred.principal)
return NULL;
if (RPC_IS_ASYNC(task))
lookupflags |= RPCAUTH_LOOKUP_ASYNC;
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)
};
if (flags & RPC_TASK_ASYNC)
lookupflags |= RPCAUTH_LOOKUP_NEW;
lookupflags |= RPCAUTH_LOOKUP_NEW | RPCAUTH_LOOKUP_ASYNC;
if (task->tk_op_cred)
/* Task must use exactly this rpc_cred */
new = get_rpccred(task->tk_op_cred);
@ -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 (new)
;
else if (cred == &machine_cred || (flags & RPC_TASK_ROOTCREDS))
else if (cred == &machine_cred)
new = rpcauth_bind_root_cred(task, lookupflags);
else if (flags & RPC_TASK_NULLCREDS)
new = authnull_ops.lookup_cred(NULL, NULL, 0);

View File

@ -146,7 +146,7 @@ gss_alloc_context(void)
{
struct gss_cl_ctx *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_NOFS);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
ctx->gc_proc = RPC_GSS_PROC_DATA;
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
p = ERR_PTR(-EFAULT);
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) {
trace_rpcgss_import_ctx(ret);
p = ERR_PTR(ret);
@ -511,7 +511,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
int vers;
int err = -ENOMEM;
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL);
if (gss_msg == NULL)
goto err;
vers = get_pipe_version(gss_auth->net);
@ -527,7 +527,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
gss_msg->auth = gss_auth;
kref_get(&gss_auth->kref);
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) {
err = -ENOMEM;
goto err_put_pipe_version;
@ -703,7 +703,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (mlen > MSG_BUF_MAXSIZE)
goto out;
err = -ENOMEM;
buf = kmalloc(mlen, GFP_NOFS);
buf = kmalloc(mlen, GFP_KERNEL);
if (!buf)
goto out;
@ -1220,7 +1220,7 @@ gss_dup_cred(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
struct gss_cred *new;
/* 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) {
struct auth_cred acred = {
.cred = gss_cred->gc_base.cr_cred,
@ -1343,7 +1343,11 @@ gss_hash_cred(struct auth_cred *acred, unsigned int hashbits)
static struct rpc_cred *
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 *
@ -1669,7 +1673,7 @@ gss_validate(struct rpc_task *task, struct xdr_stream *xdr)
if (!p)
goto validate_failed;
seq = kmalloc(4, GFP_NOFS);
seq = kmalloc(4, GFP_KERNEL);
if (!seq)
goto validate_failed;
*seq = cpu_to_be32(task->tk_rqstp->rq_seqno);
@ -1779,11 +1783,11 @@ alloc_enc_pages(struct rpc_rqst *rqstp)
rqstp->rq_enc_pages
= kmalloc_array(rqstp->rq_enc_pages_num,
sizeof(struct page *),
GFP_NOFS);
GFP_KERNEL);
if (!rqstp->rq_enc_pages)
goto out;
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)
goto out_free;
}
@ -1987,7 +1991,7 @@ gss_unwrap_resp_integ(struct rpc_task *task, struct rpc_cred *cred,
if (offset + len > rcv_buf->len)
goto unwrap_failed;
mic.len = len;
mic.data = kmalloc(len, GFP_NOFS);
mic.data = kmalloc(len, GFP_KERNEL);
if (!mic.data)
goto unwrap_failed;
if (read_bytes_from_xdr_buf(rcv_buf, offset, mic.data, mic.len))

View File

@ -35,7 +35,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
if (unlikely(q > end || q < p))
return ERR_PTR(-EFAULT);
if (len) {
dest->data = kmemdup(p, len, GFP_NOFS);
dest->data = kmemdup(p, len, GFP_KERNEL);
if (unlikely(dest->data == NULL))
return ERR_PTR(-ENOMEM);
} else

View File

@ -161,7 +161,7 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
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)
return GSS_S_FAILURE;
@ -169,7 +169,7 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
if (IS_ERR(tfm))
goto out_free_cksum;
req = ahash_request_alloc(tfm, GFP_NOFS);
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto out_free_ahash;
@ -257,7 +257,7 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
return GSS_S_FAILURE;
}
checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_KERNEL);
if (!checksumdata)
return GSS_S_FAILURE;
@ -265,7 +265,7 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
if (IS_ERR(tfm))
goto out_free_cksum;
req = ahash_request_alloc(tfm, GFP_NOFS);
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto out_free_ahash;
@ -554,7 +554,7 @@ gss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf,
WARN_ON(0);
return -ENOMEM;
}
data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_NOFS);
data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_KERNEL);
if (!data)
return -ENOMEM;

View File

@ -49,7 +49,7 @@ krb5_make_seq_num(struct krb5_ctx *kctx,
unsigned char *plain;
s32 code;
plain = kmalloc(8, GFP_NOFS);
plain = kmalloc(8, GFP_KERNEL);
if (!plain)
return -ENOMEM;
@ -80,7 +80,7 @@ krb5_get_seq_num(struct krb5_ctx *kctx,
dprintk("RPC: krb5_get_seq_num:\n");
plain = kmalloc(8, GFP_NOFS);
plain = kmalloc(8, GFP_KERNEL);
if (!plain)
return -ENOMEM;

View File

@ -409,7 +409,7 @@ static u32
gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
struct xdr_buf *buf, struct page **pages)
{
u8 *ptr, *plainhdr;
u8 *ptr;
time64_t now;
u8 flags = 0x00;
__be16 *be16ptr;
@ -426,7 +426,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
return GSS_S_FAILURE;
/* 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 & 0xff);

View File

@ -40,11 +40,19 @@ unx_destroy(struct rpc_auth *auth)
/*
* Lookup AUTH_UNIX creds for current process
*/
static struct rpc_cred *
unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
static struct rpc_cred *unx_lookup_cred(struct rpc_auth *auth,
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);
ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
return ret;

View File

@ -75,9 +75,9 @@ static int xprt_alloc_xdr_buf(struct xdr_buf *buf, gfp_t gfp_flags)
return 0;
}
static
struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt, gfp_t gfp_flags)
static struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt)
{
gfp_t gfp_flags = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
struct rpc_rqst *req;
/* Pre-allocate one backchannel rpc_rqst */
@ -154,7 +154,7 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
INIT_LIST_HEAD(&tmp_list);
for (i = 0; i < min_reqs; i++) {
/* Pre-allocate one backchannel rpc_rqst */
req = xprt_alloc_bc_req(xprt, GFP_KERNEL);
req = xprt_alloc_bc_req(xprt);
if (req == NULL) {
printk(KERN_ERR "Failed to create bc rpc_rqst\n");
goto out_free;
@ -343,7 +343,7 @@ found:
break;
} else if (req)
break;
new = xprt_alloc_bc_req(xprt, GFP_KERNEL);
new = xprt_alloc_bc_req(xprt);
} while (new);
return req;
}

View File

@ -1065,7 +1065,9 @@ rpc_task_get_next_xprt(struct rpc_clnt *clnt)
static
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;
if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN)
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)
task->tk_flags |= RPC_TASK_TIMEOUT;
if (clnt->cl_noretranstimeo)
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 */
spin_lock(&clnt->cl_lock);
list_add_tail(&task->tk_task, &clnt->cl_tasks);
@ -1745,6 +1745,9 @@ call_refreshresult(struct rpc_task *task)
task->tk_cred_retry--;
trace_rpc_retry_refresh_status(task);
return;
case -ENOMEM:
rpc_delay(task, HZ >> 4);
return;
}
trace_rpc_refresh_status(task);
rpc_call_rpcerror(task, status);
@ -2793,7 +2796,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
return -EINVAL;
}
data = kmalloc(sizeof(*data), GFP_NOFS);
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->xps = xprt_switch_get(xps);
@ -3068,6 +3071,8 @@ rpc_clnt_swap_activate_callback(struct rpc_clnt *clnt,
int
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)
return rpc_clnt_iterate_for_each_xprt(clnt,
rpc_clnt_swap_activate_callback, NULL);

View File

@ -714,7 +714,7 @@ void rpcb_getport_async(struct rpc_task *task)
goto bailout_nofree;
}
map = kzalloc(sizeof(struct rpcbind_args), GFP_NOFS);
map = kzalloc(sizeof(struct rpcbind_args), rpc_task_gfp_mask());
if (!map) {
status = -ENOMEM;
goto bailout_release_client;
@ -730,7 +730,7 @@ void rpcb_getport_async(struct rpc_task *task)
case RPCBVERS_4:
case RPCBVERS_3:
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) {
status = -ENOMEM;
goto bailout_free_args;

View File

@ -57,6 +57,13 @@ struct workqueue_struct *rpciod_workqueue __read_mostly;
struct workqueue_struct *xprtiod_workqueue __read_mostly;
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
rpc_task_timeout(const struct rpc_task *task)
{
@ -186,11 +193,6 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *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,
struct rpc_task *task,
@ -199,8 +201,6 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
INIT_LIST_HEAD(&task->u.tk_wait.timer_list);
if (RPC_IS_PRIORITY(queue))
__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
list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
task->tk_waitqueue = queue;
@ -876,6 +876,15 @@ void rpc_release_calldata(const struct rpc_call_ops *ops, void *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).
*/
@ -884,6 +893,7 @@ static void __rpc_execute(struct rpc_task *task)
struct rpc_wait_queue *queue;
int task_is_async = RPC_IS_ASYNC(task);
int status = 0;
unsigned long pflags = current->flags;
WARN_ON_ONCE(RPC_IS_QUEUED(task));
if (RPC_IS_QUEUED(task))
@ -906,6 +916,10 @@ static void __rpc_execute(struct rpc_task *task)
}
if (!do_action)
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);
do_action(task);
@ -943,7 +957,7 @@ static void __rpc_execute(struct rpc_task *task)
rpc_clear_running(task);
spin_unlock(&queue->lock);
if (task_is_async)
return;
goto out;
/* sync task: sleep here */
trace_rpc_task_sync_sleep(task, task->tk_action);
@ -967,6 +981,8 @@ static void __rpc_execute(struct rpc_task *task)
/* Release all resources associated with the task */
rpc_release_task(task);
out:
current_restore_flags(pflags, PF_MEMALLOC);
}
/*
@ -1021,15 +1037,15 @@ int rpc_malloc(struct rpc_task *task)
struct rpc_rqst *rqst = task->tk_rqstp;
size_t size = rqst->rq_callsize + rqst->rq_rcvsize;
struct rpc_buffer *buf;
gfp_t gfp = GFP_NOFS;
if (RPC_IS_SWAPPER(task))
gfp = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN;
gfp_t gfp = rpc_task_gfp_mask();
size += sizeof(struct rpc_buffer);
if (size <= RPC_BUFFER_MAXSIZE)
buf = mempool_alloc(rpc_buffer_mempool, gfp);
else
if (size <= RPC_BUFFER_MAXSIZE) {
buf = kmem_cache_alloc(rpc_buffer_slabp, gfp);
/* 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);
if (!buf)
@ -1092,10 +1108,14 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
rpc_init_task_statistics(task);
}
static struct rpc_task *
rpc_alloc_task(void)
static struct rpc_task *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);
}
/*

View File

@ -15,6 +15,7 @@
#include <linux/pagemap.h>
#include <linux/udp.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xdr.h>
#include <linux/export.h>
@ -222,7 +223,7 @@ static int xprt_send_pagedata(struct socket *sock, struct msghdr *msg,
{
int err;
err = xdr_alloc_bvec(xdr, GFP_KERNEL);
err = xdr_alloc_bvec(xdr, rpc_task_gfp_mask());
if (err < 0)
return err;

View File

@ -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);
ssize_t ret;
if (!xprt)
return 0;
if (!xprt) {
ret = sprintf(buf, "<closed>\n");
goto out;
}
ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
xprt_put(xprt);
return ret + 1;
out:
return ret;
}
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)
{
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
struct sockaddr_storage saddr;
struct sock_xprt *sock;
ssize_t ret = -1;
if (!xprt || !xprt_connected(xprt)) {
xprt_put(xprt);
return -ENOTCONN;
}
sock = container_of(xprt, struct sock_xprt, xprt);
mutex_lock(&sock->recv_mutex);
if (sock->sock == NULL ||
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);
return ret + 1;
}
static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
size_t buflen = PAGE_SIZE;
ssize_t ret;
if (!xprt || !xprt_connected(xprt)) {
xprt_put(xprt);
return -ENOTCONN;
ret = sprintf(buf, "<closed>\n");
} 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
ret = sprintf(buf, "<closed>\n");
} else
ret = sprintf(buf, "<not a socket>\n");
xprt_put(xprt);
return ret;
}
static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
unsigned short srcport = 0;
size_t buflen = PAGE_SIZE;
ssize_t ret;
if (!xprt || !xprt_connected(xprt)) {
ret = sprintf(buf, "<closed>\n");
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"
"binding_q_len=%u\nsending_q_len=%u\npending_q_len=%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,
xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
xprt->sending.qlen, xprt->pending.qlen,
xprt->backlog.qlen, xprt->main,
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
get_srcport(xprt) : 0,
xprt->backlog.qlen, xprt->main, srcport,
atomic_long_read(&xprt->queuelen),
(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
xprt->address_strings[RPC_DISPLAY_PORT] : "0");
xprt->address_strings[RPC_DISPLAY_PORT]);
out:
xprt_put(xprt);
return ret + 1;
return ret;
}
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,
closing, congested, cwnd_wait, write_space, offline, remove;
if (!xprt)
return 0;
if (!xprt->state) {
if (!(xprt && xprt->state)) {
ret = sprintf(buf, "state=CLOSED\n");
} else {
locked = test_bit(XPRT_LOCKED, &xprt->state);
@ -201,7 +203,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
}
xprt_put(xprt);
return ret + 1;
return ret;
}
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,
atomic_long_read(&xprt_switch->xps_queuelen));
xprt_switch_put(xprt_switch);
return ret + 1;
return ret;
}
static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,

View File

@ -1354,17 +1354,6 @@ xprt_request_enqueue_transmit(struct rpc_task *task)
INIT_LIST_HEAD(&req->rq_xmit2);
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) {
list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
if (pos->rq_task->tk_owner != task->tk_owner)
@ -1503,6 +1492,9 @@ bool xprt_prepare_transmit(struct rpc_task *task)
return false;
}
if (atomic_read(&xprt->swapper))
/* This will be clear in __rpc_execute */
current->flags |= PF_MEMALLOC;
return true;
}
@ -1692,7 +1684,7 @@ static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt)
goto out;
++xprt->num_reqs;
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);
if (req != NULL)
goto out;
@ -2112,7 +2104,14 @@ static void xprt_destroy(struct rpc_xprt *xprt)
*/
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);
spin_unlock(&xprt->transport_lock);
/*
* Destroy sockets etc from the system workqueue so they can

View File

@ -130,7 +130,7 @@ int frwr_mr_init(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr *mr)
if (IS_ERR(frmr))
goto out_mr_err;
sg = kmalloc_array(depth, sizeof(*sg), GFP_NOFS);
sg = kmalloc_array(depth, sizeof(*sg), GFP_KERNEL);
if (!sg)
goto out_list_err;

View File

@ -235,8 +235,11 @@ xprt_rdma_connect_worker(struct work_struct *work)
struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt,
rx_connect_worker.work);
struct rpc_xprt *xprt = &r_xprt->rx_xprt;
unsigned int pflags = current->flags;
int rc;
if (atomic_read(&xprt->swapper))
current->flags |= PF_MEMALLOC;
rc = rpcrdma_xprt_connect(r_xprt);
xprt_clear_connecting(xprt);
if (!rc) {
@ -250,6 +253,7 @@ xprt_rdma_connect_worker(struct work_struct *work)
rpcrdma_xprt_disconnect(r_xprt);
xprt_unlock_connect(xprt, r_xprt);
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)
return;
out_sleep:
task->tk_status = -EAGAIN;
task->tk_status = -ENOMEM;
xprt_add_backlog(xprt, task);
}
@ -570,8 +574,8 @@ xprt_rdma_allocate(struct rpc_task *task)
gfp_t flags;
flags = RPCRDMA_DEF_GFP;
if (RPC_IS_SWAPPER(task))
flags = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN;
if (RPC_IS_ASYNC(task))
flags = GFP_NOWAIT | __GFP_NOWARN;
if (!rpcrdma_check_regbuf(r_xprt, req->rl_sendbuf, rqst->rq_callsize,
flags))

View File

@ -373,7 +373,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
struct rpcrdma_ep *ep;
int rc;
ep = kzalloc(sizeof(*ep), GFP_NOFS);
ep = kzalloc(sizeof(*ep), GFP_KERNEL);
if (!ep)
return -ENOTCONN;
ep->re_xprt = &r_xprt->rx_xprt;
@ -746,7 +746,7 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
struct rpcrdma_mr *mr;
int rc;
mr = kzalloc(sizeof(*mr), GFP_NOFS);
mr = kzalloc(sizeof(*mr), GFP_KERNEL);
if (!mr)
break;

View File

@ -58,6 +58,7 @@
#include "sunrpc.h"
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,
struct socket *sock);
@ -427,9 +428,9 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
offset += want;
}
want = xs_alloc_sparse_pages(buf,
min_t(size_t, count - offset, buf->page_len),
GFP_KERNEL);
want = xs_alloc_sparse_pages(
buf, min_t(size_t, count - offset, buf->page_len),
GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
if (seek < want) {
ret = xs_read_bvec(sock, msg, flags, buf->bvec,
xdr_buf_pagecount(buf),
@ -763,12 +764,12 @@ xs_stream_start_connect(struct sock_xprt *transport)
/**
* xs_nospace - handle transmit was incomplete
* @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 sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct rpc_xprt *xprt = &transport->xprt;
struct sock *sk = transport->inet;
int ret = -EAGAIN;
@ -780,24 +781,44 @@ static int xs_nospace(struct rpc_rqst *req)
/* Don't race with disconnect */
if (xprt_connected(xprt)) {
/* 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++;
xprt_wait_for_buffer_space(xprt);
} else
ret = -ENOTCONN;
spin_unlock(&xprt->transport_lock);
return ret;
}
/* Race breaker in case memory is freed before above code is called */
if (ret == -EAGAIN) {
struct socket_wq *wq;
static int xs_sock_nospace(struct rpc_rqst *req)
{
struct sock_xprt *transport =
container_of(req->rq_xprt, struct sock_xprt, xprt);
struct sock *sk = transport->inet;
int ret = -EAGAIN;
rcu_read_lock();
wq = rcu_dereference(sk->sk_wq);
set_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags);
rcu_read_unlock();
lock_sock(sk);
if (!sock_writeable(sk))
ret = xs_nospace(req, transport);
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;
}
@ -805,7 +826,8 @@ static void
xs_stream_prepare_request(struct rpc_rqst *req)
{
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)
struct msghdr msg = {
.msg_flags = XS_SENDMSG_FLAGS,
};
bool vm_wait;
unsigned int sent;
int status;
@ -863,15 +886,14 @@ static int xs_local_send_request(struct rpc_rqst *req)
xs_pktdump("packet data:",
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();
status = xprt_sock_sendmsg(transport->sock, &msg, xdr,
transport->xmit.offset, rm, &sent);
dprintk("RPC: %s(%u) = %d\n",
__func__, xdr->len - transport->xmit.offset, status);
if (status == -EAGAIN && sock_writeable(transport->inet))
status = -ENOBUFS;
if (likely(sent > 0) || status == 0) {
transport->xmit.offset += sent;
req->rq_bytes_sent = transport->xmit.offset;
@ -881,13 +903,12 @@ static int xs_local_send_request(struct rpc_rqst *req)
return 0;
}
status = -EAGAIN;
vm_wait = false;
}
switch (status) {
case -ENOBUFS:
break;
case -EAGAIN:
status = xs_nospace(req);
status = xs_stream_nospace(req, vm_wait);
break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
@ -963,7 +984,7 @@ process_status:
/* Should we call xs_close() here? */
break;
case -EAGAIN:
status = xs_nospace(req);
status = xs_sock_nospace(req);
break;
case -ENETUNREACH:
case -ENOBUFS:
@ -1005,7 +1026,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
struct msghdr msg = {
.msg_flags = XS_SENDMSG_FLAGS,
};
bool vm_wait = false;
bool vm_wait;
unsigned int sent;
int status;
@ -1025,12 +1046,17 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state))
xs_tcp_set_socket_timeouts(xprt, transport->sock);
xs_set_srcport(transport, transport->sock);
/* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have
* called sendmsg(). */
req->rq_xtime = ktime_get();
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,
transport->xmit.offset, rm, &sent);
@ -1051,31 +1077,10 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
WARN_ON_ONCE(sent == 0 && status == 0);
if (status == -EAGAIN ) {
/*
* 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;
}
if (sent > 0)
vm_wait = false;
} while (status == 0);
switch (status) {
case -ENOTSOCK:
@ -1083,7 +1088,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
/* Should we call xs_close() here? */
break;
case -EAGAIN:
status = xs_nospace(req);
status = xs_stream_nospace(req, vm_wait);
break;
case -ECONNRESET:
case -ECONNREFUSED:
@ -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_WRITE, &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)
@ -1470,7 +1476,6 @@ static void xs_tcp_state_change(struct sock *sk)
static void xs_write_space(struct sock *sk)
{
struct socket_wq *wq;
struct sock_xprt *transport;
struct rpc_xprt *xprt;
@ -1481,15 +1486,10 @@ static void xs_write_space(struct sock *sk)
if (unlikely(!(xprt = xprt_from_sock(sk))))
return;
transport = container_of(xprt, struct sock_xprt, xprt);
rcu_read_lock();
wq = rcu_dereference(sk->sk_wq);
if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
goto out;
if (!test_and_clear_bit(XPRT_SOCK_NOSPACE, &transport->sock_state))
return;
xs_run_error_worker(transport, XPRT_SOCK_WAKE_WRITE);
sk->sk_write_pending--;
out:
rcu_read_unlock();
}
/**
@ -1638,7 +1638,7 @@ static int xs_get_srcport(struct sock_xprt *transport)
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);
unsigned short ret = 0;
@ -1648,7 +1648,25 @@ unsigned short get_srcport(struct rpc_xprt *xprt)
mutex_unlock(&sock->recv_mutex);
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)
{
@ -1830,7 +1848,6 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,
sk->sk_user_data = xprt;
sk->sk_data_ready = xs_data_ready;
sk->sk_write_space = xs_udp_write_space;
sock_set_flag(sk, SOCK_FASYNC);
sk->sk_error_report = xs_error_report;
xprt_clear_connected(xprt);
@ -1936,9 +1953,9 @@ static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task)
#if IS_ENABLED(CONFIG_SUNRPC_SWAP)
/*
* Note that this should be called with XPRT_LOCKED held (or when we otherwise
* know that we have exclusive access to the socket), to guard against
* races with xs_reset_transport.
* Note that this should be called with XPRT_LOCKED held, or recv_mutex
* held, or when we otherwise know that we have exclusive access to the
* socket, to guard against races with xs_reset_transport.
*/
static void xs_set_memalloc(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);
if (atomic_inc_return(&xprt->swapper) != 1)
return 0;
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE))
return -ERESTARTSYS;
if (xs->inet)
mutex_lock(&xs->recv_mutex);
if (atomic_inc_return(&xprt->swapper) == 1 &&
xs->inet)
sk_set_memalloc(xs->inet);
xprt_release_xprt(xprt, NULL);
mutex_unlock(&xs->recv_mutex);
return 0;
}
@ -1989,13 +2004,11 @@ xs_disable_swap(struct rpc_xprt *xprt)
{
struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt);
if (!atomic_dec_and_test(&xprt->swapper))
return;
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE))
return;
if (xs->inet)
mutex_lock(&xs->recv_mutex);
if (atomic_dec_and_test(&xprt->swapper) &&
xs->inet)
sk_clear_memalloc(xs->inet);
xprt_release_xprt(xprt, NULL);
mutex_unlock(&xs->recv_mutex);
}
#else
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)
sk->sk_user_data = xprt;
sk->sk_data_ready = xs_data_ready;
sk->sk_write_space = xs_udp_write_space;
sock_set_flag(sk, SOCK_FASYNC);
xprt_set_connected(xprt);
@ -2052,7 +2064,10 @@ static void xs_udp_setup_socket(struct work_struct *work)
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock;
int status = -EIO;
unsigned int pflags = current->flags;
if (atomic_read(&xprt->swapper))
current->flags |= PF_MEMALLOC;
sock = xs_create_sock(xprt, transport,
xs_addr(xprt)->sa_family, SOCK_DGRAM,
IPPROTO_UDP, false);
@ -2072,6 +2087,7 @@ out:
xprt_clear_connecting(xprt);
xprt_unlock_connect(xprt, transport);
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)
sk->sk_data_ready = xs_data_ready;
sk->sk_state_change = xs_tcp_state_change;
sk->sk_write_space = xs_tcp_write_space;
sock_set_flag(sk, SOCK_FASYNC);
sk->sk_error_report = xs_error_report;
/* socket options */
@ -2231,11 +2246,19 @@ static void xs_tcp_setup_socket(struct work_struct *work)
struct socket *sock = transport->sock;
struct rpc_xprt *xprt = &transport->xprt;
int status;
unsigned int pflags = current->flags;
if (!sock) {
sock = xs_create_sock(xprt, transport,
xs_addr(xprt)->sa_family, SOCK_STREAM,
IPPROTO_TCP, true);
if (atomic_read(&xprt->swapper))
current->flags |= PF_MEMALLOC;
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)) {
xprt_wake_pending_tasks(xprt, PTR_ERR(sock));
goto out;
@ -2255,10 +2278,9 @@ static void xs_tcp_setup_socket(struct work_struct *work)
sock->sk->sk_state);
switch (status) {
case 0:
xs_set_srcport(transport, sock);
fallthrough;
case -EINPROGRESS:
/* SYN_SENT! */
set_bit(XPRT_SOCK_CONNECT_SENT, &transport->sock_state);
if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
fallthrough;
@ -2296,6 +2318,7 @@ out:
xprt_clear_connecting(xprt);
out_unlock:
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)
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 "
"seconds\n",
xprt, xprt->reestablish_timeout / HZ);
/* Start by resetting any existing state */
xs_reset_transport(transport);
"seconds\n", xprt, xprt->reestablish_timeout / HZ);
delay = xprt_reconnect_delay(xprt);
xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO);
@ -2487,7 +2506,7 @@ static int bc_malloc(struct rpc_task *task)
return -EINVAL;
}
page = alloc_page(GFP_KERNEL);
page = alloc_page(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
if (!page)
return -ENOMEM;
@ -2621,6 +2640,8 @@ static const struct rpc_xprt_ops xs_udp_ops = {
.rpcbind = rpcb_getport_async,
.set_port = xs_set_port,
.connect = xs_connect,
.get_srcaddr = xs_sock_srcaddr,
.get_srcport = xs_sock_srcport,
.buf_alloc = rpc_malloc,
.buf_free = rpc_free,
.send_request = xs_udp_send_request,
@ -2643,6 +2664,8 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
.rpcbind = rpcb_getport_async,
.set_port = xs_set_port,
.connect = xs_connect,
.get_srcaddr = xs_sock_srcaddr,
.get_srcport = xs_sock_srcport,
.buf_alloc = rpc_malloc,
.buf_free = rpc_free,
.prepare_request = xs_stream_prepare_request,