Merge tag 'nfs-for-6.18-1' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client updates from Anna Schumaker:
 "New Features:
   - Add a Kconfig option to redirect dfprintk() to the trace buffer
   - Enable use of the RWF_DONTCACHE flag on the NFS client
   - Add striped layout handling to pNFS flexfiles
   - Add proper localio handling for READ and WRITE O_DIRECT

  Bugfixes:
   - Handle NFS4ERR_GRACE errors during delegation recall
   - Fix NFSv4.1 backchannel max_resp_sz verification check
   - Fix mount hang after CREATE_SESSION failure
   - Fix d_parent->d_inode locking in nfs4_setup_readdir()

  Other Cleanups and Improvements:
   - Improvements to write handling tracepoints
   - Fix a few trivial spelling mistakes
   - Cleanups to the rpcbind cleanup call sites
   - Convert the SUNRPC xdr_buf to use a scratch folio instead of
     scratch page
   - Remove unused NFS_WBACK_BUSY() macro
   - Remove __GFP_NOWARN flags
   - Unexport rpc_malloc() and rpc_free()"

* tag 'nfs-for-6.18-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (46 commits)
  NFS: add basic STATX_DIOALIGN and STATX_DIO_READ_ALIGN support
  nfs/localio: add tracepoints for misaligned DIO READ and WRITE support
  nfs/localio: add proper O_DIRECT support for READ and WRITE
  nfs/localio: refactor iocb initialization
  nfs/localio: refactor iocb and iov_iter_bvec initialization
  nfs/localio: avoid issuing misaligned IO using O_DIRECT
  nfs/localio: make trace_nfs_local_open_fh more useful
  NFSD: filecache: add STATX_DIOALIGN and STATX_DIO_READ_ALIGN support
  sunrpc: unexport rpc_malloc() and rpc_free()
  NFSv4/flexfiles: Add support for striped layouts
  NFSv4/flexfiles: Update layout stats & error paths for striped layouts
  NFSv4/flexfiles: Write path updates for striped layouts
  NFSv4/flexfiles: Commit path updates for striped layouts
  NFSv4/flexfiles: Read path updates for striped layouts
  NFSv4/flexfiles: Update low level helper functions to be DS stripe aware.
  NFSv4/flexfiles: Add data structure support for striped layouts
  NFSv4/flexfiles: Use ds_commit_idx when marking a write commit
  NFSv4/flexfiles: Remove cred local variable dependency
  nfs4_setup_readdir(): insufficient locking for ->d_parent->d_inode dereferencing
  NFS: Enable use of the RWF_DONTCACHE flag on the NFS client
  ...
This commit is contained in:
Linus Torvalds
2025-10-03 14:20:40 -07:00
48 changed files with 1469 additions and 556 deletions

View File

@@ -216,8 +216,7 @@ out_err:
if (warned++ == 0)
printk(KERN_WARNING
"lockd_up: makesock failed, error=%d\n", err);
svc_xprt_destroy_all(serv, net);
svc_rpcb_cleanup(serv, net);
svc_xprt_destroy_all(serv, net, true);
return err;
}
@@ -255,8 +254,7 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)
nlm_shutdown_hosts_net(net);
cancel_delayed_work_sync(&ln->grace_period_end);
locks_end_grace(&ln->lockd_manager);
svc_xprt_destroy_all(serv, net);
svc_rpcb_cleanup(serv, net);
svc_xprt_destroy_all(serv, net, true);
}
} else {
pr_err("%s: no users! net=%x\n",

View File

@@ -676,7 +676,7 @@ bl_alloc_lseg(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr,
struct pnfs_layout_segment *lseg;
struct xdr_buf buf;
struct xdr_stream xdr;
struct page *scratch;
struct folio *scratch;
int status, i;
uint32_t count;
__be32 *p;
@@ -689,13 +689,13 @@ bl_alloc_lseg(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr,
return ERR_PTR(-ENOMEM);
status = -ENOMEM;
scratch = alloc_page(gfp_mask);
scratch = folio_alloc(gfp_mask, 0);
if (!scratch)
goto out;
xdr_init_decode_pages(&xdr, &buf,
lgr->layoutp->pages, lgr->layoutp->len);
xdr_set_scratch_page(&xdr, scratch);
xdr_set_scratch_folio(&xdr, scratch);
status = -EIO;
p = xdr_inline_decode(&xdr, 4);
@@ -744,7 +744,7 @@ process_extents:
}
out_free_scratch:
__free_page(scratch);
folio_put(scratch);
out:
dprintk("%s returns %d\n", __func__, status);
switch (status) {

View File

@@ -541,16 +541,16 @@ bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
struct pnfs_block_dev *top;
struct xdr_stream xdr;
struct xdr_buf buf;
struct page *scratch;
struct folio *scratch;
int nr_volumes, ret, i;
__be32 *p;
scratch = alloc_page(gfp_mask);
scratch = folio_alloc(gfp_mask, 0);
if (!scratch)
goto out;
xdr_init_decode_pages(&xdr, &buf, pdev->pages, pdev->pglen);
xdr_set_scratch_page(&xdr, scratch);
xdr_set_scratch_folio(&xdr, scratch);
p = xdr_inline_decode(&xdr, sizeof(__be32));
if (!p)
@@ -582,7 +582,7 @@ bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
out_free_volumes:
kfree(volumes);
out_free_scratch:
__free_page(scratch);
folio_put(scratch);
out:
return node;
}

View File

@@ -136,7 +136,7 @@ static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struc
return;
dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum);
svc_xprt_destroy_all(serv, net);
svc_xprt_destroy_all(serv, net, false);
}
static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
@@ -153,7 +153,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
ret = svc_bind(serv, net);
if (ret < 0) {
printk(KERN_WARNING "NFS: bind callback service failed\n");
goto err_bind;
goto err;
}
ret = 0;
@@ -166,13 +166,11 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
if (ret < 0) {
printk(KERN_ERR "NFS: callback service start failed\n");
goto err_socks;
goto err;
}
return 0;
err_socks:
svc_rpcb_cleanup(serv, net);
err_bind:
err:
nn->cb_users[minorversion]--;
dprintk("NFS: Couldn't create callback socket: err = %d; "
"net = %x\n", ret, net->ns.inum);

View File

@@ -829,17 +829,17 @@ static int nfs_readdir_folio_filler(struct nfs_readdir_descriptor *desc,
struct address_space *mapping = desc->file->f_mapping;
struct folio *new, *folio = *arrays;
struct xdr_stream stream;
struct page *scratch;
struct folio *scratch;
struct xdr_buf buf;
u64 cookie;
int status;
scratch = alloc_page(GFP_KERNEL);
scratch = folio_alloc(GFP_KERNEL, 0);
if (scratch == NULL)
return -ENOMEM;
xdr_init_decode_pages(&stream, &buf, xdr_pages, buflen);
xdr_set_scratch_page(&stream, scratch);
xdr_set_scratch_folio(&stream, scratch);
do {
status = nfs_readdir_entry_decode(desc, entry, &stream);
@@ -891,7 +891,7 @@ static int nfs_readdir_folio_filler(struct nfs_readdir_descriptor *desc,
if (folio != *arrays)
nfs_readdir_folio_unlock_and_put(folio);
put_page(scratch);
folio_put(scratch);
return status;
}

View File

@@ -161,6 +161,8 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
struct inode *inode = file_inode(iocb->ki_filp);
ssize_t result;
trace_nfs_file_read(iocb, to);
if (iocb->ki_flags & IOCB_DIRECT)
return nfs_file_direct_read(iocb, to, false);
@@ -361,6 +363,8 @@ static bool nfs_want_read_modify_write(struct file *file, struct folio *folio,
if (pnfs_ld_read_whole_page(file_inode(file)))
return true;
if (folio_test_dropbehind(folio))
return false;
/* Open for reading too? */
if (file->f_mode & FMODE_READ)
return true;
@@ -380,22 +384,23 @@ static int nfs_write_begin(const struct kiocb *iocb,
loff_t pos, unsigned len, struct folio **foliop,
void **fsdata)
{
fgf_t fgp = FGP_WRITEBEGIN;
struct folio *folio;
struct file *file = iocb->ki_filp;
int once_thru = 0;
int ret;
trace_nfs_write_begin(file_inode(file), pos, len);
dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n",
file, mapping->host->i_ino, len, (long long) pos);
nfs_truncate_last_folio(mapping, i_size_read(mapping->host), pos);
fgp |= fgf_set_order(len);
start:
folio = __filemap_get_folio(mapping, pos >> PAGE_SHIFT, fgp,
mapping_gfp_mask(mapping));
if (IS_ERR(folio))
return PTR_ERR(folio);
folio = write_begin_get_folio(iocb, mapping, pos >> PAGE_SHIFT, len);
if (IS_ERR(folio)) {
ret = PTR_ERR(folio);
goto out;
}
*foliop = folio;
ret = nfs_flush_incompatible(file, folio);
@@ -405,11 +410,14 @@ start:
} else if (!once_thru &&
nfs_want_read_modify_write(file, folio, pos, len)) {
once_thru = 1;
folio_clear_dropbehind(folio);
ret = nfs_read_folio(file, folio);
folio_put(folio);
if (!ret)
goto start;
}
out:
trace_nfs_write_begin_done(file_inode(file), pos, len, ret);
return ret;
}
@@ -423,6 +431,7 @@ static int nfs_write_end(const struct kiocb *iocb,
unsigned offset = offset_in_folio(folio, pos);
int status;
trace_nfs_write_end(file_inode(file), pos, len);
dfprintk(PAGECACHE, "NFS: write_end(%pD2(%lu), %u@%lld)\n",
file, mapping->host->i_ino, len, (long long) pos);
@@ -451,13 +460,16 @@ static int nfs_write_end(const struct kiocb *iocb,
folio_unlock(folio);
folio_put(folio);
if (status < 0)
if (status < 0) {
trace_nfs_write_end_done(file_inode(file), pos, len, status);
return status;
}
NFS_I(mapping->host)->write_io += copied;
if (nfs_ctx_key_to_expire(ctx, mapping->host))
nfs_wb_all(mapping->host);
trace_nfs_write_end_done(file_inode(file), pos, len, copied);
return copied;
}
@@ -690,6 +702,8 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
errseq_t since;
int error;
trace_nfs_file_write(iocb, from);
result = nfs_key_timeout_notify(file, inode);
if (result)
return result;
@@ -949,5 +963,6 @@ const struct file_operations nfs_file_operations = {
.splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags,
.setlease = simple_nosetlease,
.fop_flags = FOP_DONTCACHE,
};
EXPORT_SYMBOL_GPL(nfs_file_operations);

View File

@@ -646,19 +646,19 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
{
struct xdr_stream stream;
struct xdr_buf buf;
struct page *scratch;
struct folio *scratch;
__be32 *p;
uint32_t nfl_util;
int i;
dprintk("%s: set_layout_map Begin\n", __func__);
scratch = alloc_page(gfp_flags);
scratch = folio_alloc(gfp_flags, 0);
if (!scratch)
return -ENOMEM;
xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
xdr_set_scratch_page(&stream, scratch);
xdr_set_scratch_folio(&stream, scratch);
/* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
* num_fh (4) */
@@ -724,11 +724,11 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
fl->fh_array[i]->size);
}
__free_page(scratch);
folio_put(scratch);
return 0;
out_err:
__free_page(scratch);
folio_put(scratch);
return -EIO;
}

View File

@@ -73,18 +73,18 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
struct nfs4_file_layout_dsaddr *dsaddr = NULL;
struct xdr_stream stream;
struct xdr_buf buf;
struct page *scratch;
struct folio *scratch;
struct list_head dsaddrs;
struct nfs4_pnfs_ds_addr *da;
struct net *net = server->nfs_client->cl_net;
/* set up xdr stream */
scratch = alloc_page(gfp_flags);
scratch = folio_alloc(gfp_flags, 0);
if (!scratch)
goto out_err;
xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
xdr_set_scratch_page(&stream, scratch);
xdr_set_scratch_folio(&stream, scratch);
/* Get the stripe count (number of stripe index) */
p = xdr_inline_decode(&stream, 4);
@@ -186,7 +186,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
}
}
__free_page(scratch);
folio_put(scratch);
return dsaddr;
out_err_drain_dsaddrs:
@@ -204,7 +204,7 @@ out_err_free_deviceid:
out_err_free_stripe_indices:
kfree(stripe_indices);
out_err_free_scratch:
__free_page(scratch);
folio_put(scratch);
out_err:
dprintk("%s ERROR: returning NULL\n", __func__);
return NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,8 @@
* due to network error etc. */
#define NFS4_FLEXFILE_LAYOUT_MAX_MIRROR_CNT 4096
#define NFS4_FLEXFILE_LAYOUT_MAX_STRIPE_CNT 4096
/* LAYOUTSTATS report interval in ms */
#define FF_LAYOUTSTATS_REPORT_INTERVAL (60000L)
#define FF_LAYOUTSTATS_MAXDEV 4
@@ -71,12 +73,12 @@ struct nfs4_ff_layoutstat {
struct nfs4_ff_busy_timer busy_timer;
};
struct nfs4_ff_layout_mirror {
struct pnfs_layout_hdr *layout;
struct list_head mirrors;
u32 ds_count;
u32 efficiency;
struct nfs4_ff_layout_mirror;
struct nfs4_ff_layout_ds_stripe {
struct nfs4_ff_layout_mirror *mirror;
struct nfs4_deviceid devid;
u32 efficiency;
struct nfs4_ff_layout_ds *mirror_ds;
u32 fh_versions_cnt;
struct nfs_fh *fh_versions;
@@ -84,12 +86,19 @@ struct nfs4_ff_layout_mirror {
const struct cred __rcu *ro_cred;
const struct cred __rcu *rw_cred;
struct nfs_file_localio nfl;
refcount_t ref;
spinlock_t lock;
unsigned long flags;
struct nfs4_ff_layoutstat read_stat;
struct nfs4_ff_layoutstat write_stat;
ktime_t start_time;
};
struct nfs4_ff_layout_mirror {
struct pnfs_layout_hdr *layout;
struct list_head mirrors;
u32 dss_count;
struct nfs4_ff_layout_ds_stripe *dss;
refcount_t ref;
spinlock_t lock;
unsigned long flags;
u32 report_interval;
};
@@ -150,12 +159,12 @@ FF_LAYOUT_COMP(struct pnfs_layout_segment *lseg, u32 idx)
}
static inline struct nfs4_deviceid_node *
FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx)
FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx, u32 dss_id)
{
struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, idx);
if (mirror != NULL) {
struct nfs4_ff_layout_ds *mirror_ds = mirror->mirror_ds;
struct nfs4_ff_layout_ds *mirror_ds = mirror->dss[dss_id].mirror_ds;
if (!IS_ERR_OR_NULL(mirror_ds))
return &mirror_ds->id_node;
@@ -182,9 +191,22 @@ ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg)
}
static inline int
nfs4_ff_layout_ds_version(const struct nfs4_ff_layout_mirror *mirror)
nfs4_ff_layout_ds_version(const struct nfs4_ff_layout_mirror *mirror, u32 dss_id)
{
return mirror->mirror_ds->ds_versions[0].version;
return mirror->dss[dss_id].mirror_ds->ds_versions[0].version;
}
static inline u32
nfs4_ff_layout_calc_dss_id(const u64 stripe_unit, const u32 dss_count, const loff_t offset)
{
u64 tmp = offset;
if (dss_count == 1 || stripe_unit == 0)
return 0;
do_div(tmp, stripe_unit);
return do_div(tmp, dss_count);
}
struct nfs4_ff_layout_ds *
@@ -193,9 +215,9 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds);
void nfs4_ff_layout_free_deviceid(struct nfs4_ff_layout_ds *mirror_ds);
int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
struct nfs4_ff_layout_mirror *mirror, u64 offset,
u64 length, int status, enum nfs_opnum4 opnum,
gfp_t gfp_flags);
struct nfs4_ff_layout_mirror *mirror,
u32 dss_id, u64 offset, u64 length, int status,
enum nfs_opnum4 opnum, gfp_t gfp_flags);
void ff_layout_send_layouterror(struct pnfs_layout_segment *lseg);
int ff_layout_encode_ds_ioerr(struct xdr_stream *xdr, const struct list_head *head);
void ff_layout_free_ds_ioerr(struct list_head *head);
@@ -204,23 +226,27 @@ unsigned int ff_layout_fetch_ds_ioerr(struct pnfs_layout_hdr *lo,
struct list_head *head,
unsigned int maxnum);
struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror);
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror, u32 dss_id);
void
nfs4_ff_layout_select_ds_stateid(const struct nfs4_ff_layout_mirror *mirror,
nfs4_stateid *stateid);
u32 dss_id,
nfs4_stateid *stateid);
struct nfs4_pnfs_ds *
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
struct nfs4_ff_layout_mirror *mirror,
u32 dss_id,
bool fail_return);
struct rpc_clnt *
nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror *mirror,
struct nfs_client *ds_clp,
struct inode *inode);
struct inode *inode,
u32 dss_id);
const struct cred *ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror *mirror,
const struct pnfs_layout_range *range,
const struct cred *mdscred);
const struct cred *mdscred,
u32 dss_id);
bool ff_layout_avoid_mds_available_ds(struct pnfs_layout_segment *lseg);
bool ff_layout_avoid_read_on_rw(struct pnfs_layout_segment *lseg);

View File

@@ -44,7 +44,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
{
struct xdr_stream stream;
struct xdr_buf buf;
struct page *scratch;
struct folio *scratch;
struct list_head dsaddrs;
struct nfs4_pnfs_ds_addr *da;
struct nfs4_ff_layout_ds *new_ds = NULL;
@@ -56,7 +56,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
int i, ret = -ENOMEM;
/* set up xdr stream */
scratch = alloc_page(gfp_flags);
scratch = folio_alloc(gfp_flags, 0);
if (!scratch)
goto out_err;
@@ -70,7 +70,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
INIT_LIST_HEAD(&dsaddrs);
xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
xdr_set_scratch_page(&stream, scratch);
xdr_set_scratch_folio(&stream, scratch);
/* multipath count */
p = xdr_inline_decode(&stream, 4);
@@ -163,7 +163,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
kfree(da);
}
__free_page(scratch);
folio_put(scratch);
return new_ds;
out_err_drain_dsaddrs:
@@ -177,7 +177,7 @@ out_err_drain_dsaddrs:
kfree(ds_versions);
out_scratch:
__free_page(scratch);
folio_put(scratch);
out_err:
kfree(new_ds);
@@ -250,16 +250,16 @@ ff_layout_add_ds_error_locked(struct nfs4_flexfile_layout *flo,
}
int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
struct nfs4_ff_layout_mirror *mirror, u64 offset,
u64 length, int status, enum nfs_opnum4 opnum,
gfp_t gfp_flags)
struct nfs4_ff_layout_mirror *mirror,
u32 dss_id, u64 offset, u64 length, int status,
enum nfs_opnum4 opnum, gfp_t gfp_flags)
{
struct nfs4_ff_layout_ds_err *dserr;
if (status == 0)
return 0;
if (IS_ERR_OR_NULL(mirror->mirror_ds))
if (IS_ERR_OR_NULL(mirror->dss[dss_id].mirror_ds))
return -EINVAL;
dserr = kmalloc(sizeof(*dserr), gfp_flags);
@@ -271,8 +271,8 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
dserr->length = length;
dserr->status = status;
dserr->opnum = opnum;
nfs4_stateid_copy(&dserr->stateid, &mirror->stateid);
memcpy(&dserr->deviceid, &mirror->mirror_ds->id_node.deviceid,
nfs4_stateid_copy(&dserr->stateid, &mirror->dss[dss_id].stateid);
memcpy(&dserr->deviceid, &mirror->dss[dss_id].mirror_ds->id_node.deviceid,
NFS4_DEVICEID4_SIZE);
spin_lock(&flo->generic_hdr.plh_inode->i_lock);
@@ -282,14 +282,14 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
}
static const struct cred *
ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode)
ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode, u32 dss_id)
{
const struct cred *cred, __rcu **pcred;
if (iomode == IOMODE_READ)
pcred = &mirror->ro_cred;
pcred = &mirror->dss[dss_id].ro_cred;
else
pcred = &mirror->rw_cred;
pcred = &mirror->dss[dss_id].rw_cred;
rcu_read_lock();
do {
@@ -304,43 +304,45 @@ ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode)
}
struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror)
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror, u32 dss_id)
{
/* FIXME: For now assume there is only 1 version available for the DS */
return &mirror->fh_versions[0];
return &mirror->dss[dss_id].fh_versions[0];
}
void
nfs4_ff_layout_select_ds_stateid(const struct nfs4_ff_layout_mirror *mirror,
nfs4_stateid *stateid)
u32 dss_id,
nfs4_stateid *stateid)
{
if (nfs4_ff_layout_ds_version(mirror) == 4)
nfs4_stateid_copy(stateid, &mirror->stateid);
if (nfs4_ff_layout_ds_version(mirror, dss_id) == 4)
nfs4_stateid_copy(stateid, &mirror->dss[dss_id].stateid);
}
static bool
ff_layout_init_mirror_ds(struct pnfs_layout_hdr *lo,
struct nfs4_ff_layout_mirror *mirror)
struct nfs4_ff_layout_mirror *mirror,
u32 dss_id)
{
if (mirror == NULL)
goto outerr;
if (mirror->mirror_ds == NULL) {
if (mirror->dss[dss_id].mirror_ds == NULL) {
struct nfs4_deviceid_node *node;
struct nfs4_ff_layout_ds *mirror_ds = ERR_PTR(-ENODEV);
node = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode),
&mirror->devid, lo->plh_lc_cred,
&mirror->dss[dss_id].devid, lo->plh_lc_cred,
GFP_KERNEL);
if (node)
mirror_ds = FF_LAYOUT_MIRROR_DS(node);
/* check for race with another call to this function */
if (cmpxchg(&mirror->mirror_ds, NULL, mirror_ds) &&
if (cmpxchg(&mirror->dss[dss_id].mirror_ds, NULL, mirror_ds) &&
mirror_ds != ERR_PTR(-ENODEV))
nfs4_put_deviceid_node(node);
}
if (IS_ERR(mirror->mirror_ds))
if (IS_ERR(mirror->dss[dss_id].mirror_ds))
goto outerr;
return true;
@@ -352,6 +354,7 @@ outerr:
* nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call
* @lseg: the layout segment we're operating on
* @mirror: layout mirror describing the DS to use
* @dss_id: DS stripe id to select stripe to use
* @fail_return: return layout on connect failure?
*
* Try to prepare a DS connection to accept an RPC call. This involves
@@ -368,6 +371,7 @@ outerr:
struct nfs4_pnfs_ds *
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
struct nfs4_ff_layout_mirror *mirror,
u32 dss_id,
bool fail_return)
{
struct nfs4_pnfs_ds *ds;
@@ -376,10 +380,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
unsigned int max_payload;
int status = -EAGAIN;
if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror))
if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror, dss_id))
goto noconnect;
ds = mirror->mirror_ds->ds;
ds = mirror->dss[dss_id].mirror_ds->ds;
if (READ_ONCE(ds->ds_clp))
goto out;
/* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
@@ -388,10 +392,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
/* FIXME: For now we assume the server sent only one version of NFS
* to use for the DS.
*/
status = nfs4_pnfs_ds_connect(s, ds, &mirror->mirror_ds->id_node,
status = nfs4_pnfs_ds_connect(s, ds, &mirror->dss[dss_id].mirror_ds->id_node,
dataserver_timeo, dataserver_retrans,
mirror->mirror_ds->ds_versions[0].version,
mirror->mirror_ds->ds_versions[0].minor_version);
mirror->dss[dss_id].mirror_ds->ds_versions[0].version,
mirror->dss[dss_id].mirror_ds->ds_versions[0].minor_version);
/* connect success, check rsize/wsize limit */
if (!status) {
@@ -404,15 +408,15 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
max_payload =
nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient),
NULL);
if (mirror->mirror_ds->ds_versions[0].rsize > max_payload)
mirror->mirror_ds->ds_versions[0].rsize = max_payload;
if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
mirror->mirror_ds->ds_versions[0].wsize = max_payload;
if (mirror->dss[dss_id].mirror_ds->ds_versions[0].rsize > max_payload)
mirror->dss[dss_id].mirror_ds->ds_versions[0].rsize = max_payload;
if (mirror->dss[dss_id].mirror_ds->ds_versions[0].wsize > max_payload)
mirror->dss[dss_id].mirror_ds->ds_versions[0].wsize = max_payload;
goto out;
}
noconnect:
ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, lseg->pls_range.offset,
mirror, dss_id, lseg->pls_range.offset,
lseg->pls_range.length, NFS4ERR_NXIO,
OP_ILLEGAL, GFP_NOIO);
ff_layout_send_layouterror(lseg);
@@ -426,12 +430,13 @@ out:
const struct cred *
ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror *mirror,
const struct pnfs_layout_range *range,
const struct cred *mdscred)
const struct cred *mdscred,
u32 dss_id)
{
const struct cred *cred;
if (mirror && !mirror->mirror_ds->ds_versions[0].tightly_coupled) {
cred = ff_layout_get_mirror_cred(mirror, range->iomode);
if (mirror && !mirror->dss[dss_id].mirror_ds->ds_versions[0].tightly_coupled) {
cred = ff_layout_get_mirror_cred(mirror, range->iomode, dss_id);
if (!cred)
cred = get_cred(mdscred);
} else {
@@ -445,15 +450,17 @@ ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror *mirror,
* @mirror: pointer to the mirror
* @ds_clp: nfs_client for the DS
* @inode: pointer to inode
* @dss_id: DS stripe id
*
* Find or create a DS rpc client with th MDS server rpc client auth flavor
* in the nfs_client cl_ds_clients list.
*/
struct rpc_clnt *
nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror *mirror,
struct nfs_client *ds_clp, struct inode *inode)
struct nfs_client *ds_clp, struct inode *inode,
u32 dss_id)
{
switch (mirror->mirror_ds->ds_versions[0].version) {
switch (mirror->dss[dss_id].mirror_ds->ds_versions[0].version) {
case 3:
/* For NFSv3 DS, flavor is set when creating DS connections */
return ds_clp->cl_rpcclient;
@@ -559,16 +566,18 @@ static bool ff_read_layout_has_available_ds(struct pnfs_layout_segment *lseg)
{
struct nfs4_ff_layout_mirror *mirror;
struct nfs4_deviceid_node *devid;
u32 idx;
u32 idx, dss_id;
for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
mirror = FF_LAYOUT_COMP(lseg, idx);
if (mirror) {
if (!mirror->mirror_ds)
if (!mirror)
continue;
for (dss_id = 0; dss_id < mirror->dss_count; dss_id++) {
if (!mirror->dss[dss_id].mirror_ds)
return true;
if (IS_ERR(mirror->mirror_ds))
if (IS_ERR(mirror->dss[dss_id].mirror_ds))
continue;
devid = &mirror->mirror_ds->id_node;
devid = &mirror->dss[dss_id].mirror_ds->id_node;
if (!nfs4_test_deviceid_unavailable(devid))
return true;
}
@@ -581,17 +590,21 @@ static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg)
{
struct nfs4_ff_layout_mirror *mirror;
struct nfs4_deviceid_node *devid;
u32 idx;
u32 idx, dss_id;
for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
mirror = FF_LAYOUT_COMP(lseg, idx);
if (!mirror || IS_ERR(mirror->mirror_ds))
return false;
if (!mirror->mirror_ds)
continue;
devid = &mirror->mirror_ds->id_node;
if (nfs4_test_deviceid_unavailable(devid))
if (!mirror)
return false;
for (dss_id = 0; dss_id < mirror->dss_count; dss_id++) {
if (IS_ERR(mirror->dss[dss_id].mirror_ds))
return false;
if (!mirror->dss[dss_id].mirror_ds)
continue;
devid = &mirror->dss[dss_id].mirror_ds->id_node;
if (nfs4_test_deviceid_unavailable(devid))
return false;
}
}
return FF_LAYOUT_MIRROR_COUNT(lseg) != 0;

View File

@@ -1073,6 +1073,21 @@ out_no_revalidate:
if (S_ISDIR(inode->i_mode))
stat->blksize = NFS_SERVER(inode)->dtsize;
stat->btime = NFS_I(inode)->btime;
/* Special handling for STATX_DIOALIGN and STATX_DIO_READ_ALIGN
* - NFS doesn't have DIO alignment constraints, avoid getting
* these DIO attrs from remote and just respond with most
* accommodating limits (so client will issue supported DIO).
* - this is unintuitive, but the most coarse-grained
* dio_offset_align is the most accommodating.
*/
if ((request_mask & (STATX_DIOALIGN | STATX_DIO_READ_ALIGN)) &&
S_ISREG(inode->i_mode)) {
stat->result_mask |= STATX_DIOALIGN | STATX_DIO_READ_ALIGN;
stat->dio_mem_align = 4; /* 4-byte alignment */
stat->dio_offset_align = PAGE_SIZE;
stat->dio_read_offset_align = stat->dio_offset_align;
}
out:
trace_nfs_getattr_exit(inode, err);
return err;

View File

@@ -456,6 +456,16 @@ extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
/* localio.c */
struct nfs_local_dio {
u32 mem_align;
u32 offset_align;
loff_t middle_offset;
loff_t end_offset;
ssize_t start_len; /* Length for misaligned first extent */
ssize_t middle_len; /* Length for DIO-aligned middle extent */
ssize_t end_len; /* Length for misaligned last extent */
};
extern void nfs_local_probe_async(struct nfs_client *);
extern void nfs_local_probe_async_work(struct work_struct *);
extern struct nfsd_file *nfs_local_open_fh(struct nfs_client *,

View File

@@ -30,6 +30,8 @@
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFSLOCAL_MAX_IOS 3
struct nfs_local_kiocb {
struct kiocb kiocb;
struct bio_vec *bvec;
@@ -37,6 +39,14 @@ struct nfs_local_kiocb {
struct work_struct work;
void (*aio_complete_work)(struct work_struct *);
struct nfsd_file *localio;
/* Begin mostly DIO-specific members */
size_t end_len;
short int end_iter_index;
short int n_iters;
bool iter_is_dio_aligned[NFSLOCAL_MAX_IOS];
loff_t offset[NFSLOCAL_MAX_IOS] ____cacheline_aligned;
struct iov_iter iters[NFSLOCAL_MAX_IOS];
/* End mostly DIO-specific members */
};
struct nfs_local_fsync_ctx {
@@ -49,11 +59,6 @@ struct nfs_local_fsync_ctx {
static bool localio_enabled __read_mostly = true;
module_param(localio_enabled, bool, 0644);
static bool localio_O_DIRECT_semantics __read_mostly = false;
module_param(localio_O_DIRECT_semantics, bool, 0644);
MODULE_PARM_DESC(localio_O_DIRECT_semantics,
"LOCALIO will use O_DIRECT semantics to filesystem.");
static inline bool nfs_client_is_local(const struct nfs_client *clp)
{
return !!rcu_access_pointer(clp->cl_uuid.net);
@@ -231,13 +236,13 @@ __nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
struct nfsd_file __rcu **pnf,
const fmode_t mode)
{
int status = 0;
struct nfsd_file *localio;
localio = nfs_open_local_fh(&clp->cl_uuid, clp->cl_rpcclient,
cred, fh, nfl, pnf, mode);
if (IS_ERR(localio)) {
int status = PTR_ERR(localio);
trace_nfs_local_open_fh(fh, mode, status);
status = PTR_ERR(localio);
switch (status) {
case -ENOMEM:
case -ENXIO:
@@ -247,6 +252,7 @@ __nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
nfs_local_probe(clp);
}
}
trace_nfs_local_open_fh(fh, mode, status);
return localio;
}
@@ -281,23 +287,6 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
}
EXPORT_SYMBOL_GPL(nfs_local_open_fh);
static struct bio_vec *
nfs_bvec_alloc_and_import_pagevec(struct page **pagevec,
unsigned int npages, gfp_t flags)
{
struct bio_vec *bvec, *p;
bvec = kmalloc_array(npages, sizeof(*bvec), flags);
if (bvec != NULL) {
for (p = bvec; npages > 0; p++, pagevec++, npages--) {
p->bv_page = *pagevec;
p->bv_len = PAGE_SIZE;
p->bv_offset = 0;
}
}
return bvec;
}
static void
nfs_local_iocb_free(struct nfs_local_kiocb *iocb)
{
@@ -311,40 +300,191 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr,
{
struct nfs_local_kiocb *iocb;
iocb = kmalloc(sizeof(*iocb), flags);
iocb = kzalloc(sizeof(*iocb), flags);
if (iocb == NULL)
return NULL;
iocb->bvec = nfs_bvec_alloc_and_import_pagevec(hdr->page_array.pagevec,
hdr->page_array.npages, flags);
iocb->bvec = kmalloc_array(hdr->page_array.npages,
sizeof(struct bio_vec), flags);
if (iocb->bvec == NULL) {
kfree(iocb);
return NULL;
}
if (localio_O_DIRECT_semantics &&
test_bit(NFS_IOHDR_ODIRECT, &hdr->flags)) {
iocb->kiocb.ki_filp = file;
iocb->kiocb.ki_flags = IOCB_DIRECT;
} else
init_sync_kiocb(&iocb->kiocb, file);
init_sync_kiocb(&iocb->kiocb, file);
iocb->kiocb.ki_pos = hdr->args.offset;
iocb->hdr = hdr;
iocb->kiocb.ki_flags &= ~IOCB_APPEND;
iocb->aio_complete_work = NULL;
iocb->end_iter_index = -1;
return iocb;
}
static void
nfs_local_iter_init(struct iov_iter *i, struct nfs_local_kiocb *iocb, int dir)
static bool
nfs_is_local_dio_possible(struct nfs_local_kiocb *iocb, int rw,
size_t len, struct nfs_local_dio *local_dio)
{
struct nfs_pgio_header *hdr = iocb->hdr;
loff_t offset = hdr->args.offset;
u32 nf_dio_mem_align, nf_dio_offset_align, nf_dio_read_offset_align;
loff_t start_end, orig_end, middle_end;
iov_iter_bvec(i, dir, iocb->bvec, hdr->page_array.npages,
hdr->args.count + hdr->args.pgbase);
if (hdr->args.pgbase != 0)
iov_iter_advance(i, hdr->args.pgbase);
nfs_to->nfsd_file_dio_alignment(iocb->localio, &nf_dio_mem_align,
&nf_dio_offset_align, &nf_dio_read_offset_align);
if (rw == ITER_DEST)
nf_dio_offset_align = nf_dio_read_offset_align;
if (unlikely(!nf_dio_mem_align || !nf_dio_offset_align))
return false;
if (unlikely(nf_dio_offset_align > PAGE_SIZE))
return false;
if (unlikely(len < nf_dio_offset_align))
return false;
local_dio->mem_align = nf_dio_mem_align;
local_dio->offset_align = nf_dio_offset_align;
start_end = round_up(offset, nf_dio_offset_align);
orig_end = offset + len;
middle_end = round_down(orig_end, nf_dio_offset_align);
local_dio->middle_offset = start_end;
local_dio->end_offset = middle_end;
local_dio->start_len = start_end - offset;
local_dio->middle_len = middle_end - start_end;
local_dio->end_len = orig_end - middle_end;
if (rw == ITER_DEST)
trace_nfs_local_dio_read(hdr->inode, offset, len, local_dio);
else
trace_nfs_local_dio_write(hdr->inode, offset, len, local_dio);
return true;
}
static bool nfs_iov_iter_aligned_bvec(const struct iov_iter *i,
unsigned int addr_mask, unsigned int len_mask)
{
const struct bio_vec *bvec = i->bvec;
size_t skip = i->iov_offset;
size_t size = i->count;
if (size & len_mask)
return false;
do {
size_t len = bvec->bv_len;
if (len > size)
len = size;
if ((unsigned long)(bvec->bv_offset + skip) & addr_mask)
return false;
bvec++;
size -= len;
skip = 0;
} while (size);
return true;
}
/*
* Setup as many as 3 iov_iter based on extents described by @local_dio.
* Returns the number of iov_iter that were setup.
*/
static int
nfs_local_iters_setup_dio(struct nfs_local_kiocb *iocb, int rw,
unsigned int nvecs, size_t len,
struct nfs_local_dio *local_dio)
{
int n_iters = 0;
struct iov_iter *iters = iocb->iters;
/* Setup misaligned start? */
if (local_dio->start_len) {
iov_iter_bvec(&iters[n_iters], rw, iocb->bvec, nvecs, len);
iters[n_iters].count = local_dio->start_len;
iocb->offset[n_iters] = iocb->hdr->args.offset;
iocb->iter_is_dio_aligned[n_iters] = false;
++n_iters;
}
/* Setup misaligned end?
* If so, the end is purposely setup to be issued using buffered IO
* before the middle (which will use DIO, if DIO-aligned, with AIO).
* This creates problems if/when the end results in a partial write.
* So must save index and length of end to handle this corner case.
*/
if (local_dio->end_len) {
iov_iter_bvec(&iters[n_iters], rw, iocb->bvec, nvecs, len);
iocb->offset[n_iters] = local_dio->end_offset;
iov_iter_advance(&iters[n_iters],
local_dio->start_len + local_dio->middle_len);
iocb->iter_is_dio_aligned[n_iters] = false;
/* Save index and length of end */
iocb->end_iter_index = n_iters;
iocb->end_len = local_dio->end_len;
++n_iters;
}
/* Setup DIO-aligned middle to be issued last, to allow for
* DIO with AIO completion (see nfs_local_call_{read,write}).
*/
iov_iter_bvec(&iters[n_iters], rw, iocb->bvec, nvecs, len);
if (local_dio->start_len)
iov_iter_advance(&iters[n_iters], local_dio->start_len);
iters[n_iters].count -= local_dio->end_len;
iocb->offset[n_iters] = local_dio->middle_offset;
iocb->iter_is_dio_aligned[n_iters] =
nfs_iov_iter_aligned_bvec(&iters[n_iters],
local_dio->mem_align-1, local_dio->offset_align-1);
if (unlikely(!iocb->iter_is_dio_aligned[n_iters])) {
trace_nfs_local_dio_misaligned(iocb->hdr->inode,
iocb->hdr->args.offset, len, local_dio);
return 0; /* no DIO-aligned IO possible */
}
++n_iters;
iocb->n_iters = n_iters;
return n_iters;
}
static noinline_for_stack void
nfs_local_iters_init(struct nfs_local_kiocb *iocb, int rw)
{
struct nfs_pgio_header *hdr = iocb->hdr;
struct page **pagevec = hdr->page_array.pagevec;
unsigned long v, total;
unsigned int base;
size_t len;
v = 0;
total = hdr->args.count;
base = hdr->args.pgbase;
while (total && v < hdr->page_array.npages) {
len = min_t(size_t, total, PAGE_SIZE - base);
bvec_set_page(&iocb->bvec[v], *pagevec, len, base);
total -= len;
++pagevec;
++v;
base = 0;
}
len = hdr->args.count - total;
if (test_bit(NFS_IOHDR_ODIRECT, &hdr->flags)) {
struct nfs_local_dio local_dio;
if (nfs_is_local_dio_possible(iocb, rw, len, &local_dio) &&
nfs_local_iters_setup_dio(iocb, rw, v, len, &local_dio) != 0)
return; /* is DIO-aligned */
}
/* Use buffered IO */
iocb->offset[0] = hdr->args.offset;
iov_iter_bvec(&iocb->iters[0], rw, iocb->bvec, v, len);
iocb->n_iters = 1;
}
static void
@@ -367,23 +507,31 @@ nfs_local_pgio_init(struct nfs_pgio_header *hdr,
static void
nfs_local_pgio_done(struct nfs_pgio_header *hdr, long status)
{
/* Must handle partial completions */
if (status >= 0) {
hdr->res.count = status;
hdr->res.op_status = NFS4_OK;
hdr->task.tk_status = 0;
hdr->res.count += status;
/* @hdr was initialized to 0 (zeroed during allocation) */
if (hdr->task.tk_status == 0)
hdr->res.op_status = NFS4_OK;
} else {
hdr->res.op_status = nfs_localio_errno_to_nfs4_stat(status);
hdr->task.tk_status = status;
}
}
static void
nfs_local_iocb_release(struct nfs_local_kiocb *iocb)
{
nfs_local_file_put(iocb->localio);
nfs_local_iocb_free(iocb);
}
static void
nfs_local_pgio_release(struct nfs_local_kiocb *iocb)
{
struct nfs_pgio_header *hdr = iocb->hdr;
nfs_local_file_put(iocb->localio);
nfs_local_iocb_free(iocb);
nfs_local_iocb_release(iocb);
nfs_local_hdr_release(hdr, hdr->task.tk_ops);
}
@@ -405,7 +553,10 @@ nfs_local_read_done(struct nfs_local_kiocb *iocb, long status)
struct nfs_pgio_header *hdr = iocb->hdr;
struct file *filp = iocb->kiocb.ki_filp;
nfs_local_pgio_done(hdr, status);
if ((iocb->kiocb.ki_flags & IOCB_DIRECT) && status == -EINVAL) {
/* Underlying FS will return -EINVAL if misaligned DIO is attempted. */
pr_info_ratelimited("nfs: Unexpected direct I/O read alignment failure\n");
}
/*
* Must clear replen otherwise NFSv3 data corruption will occur
@@ -434,6 +585,7 @@ static void nfs_local_read_aio_complete(struct kiocb *kiocb, long ret)
struct nfs_local_kiocb *iocb =
container_of(kiocb, struct nfs_local_kiocb, kiocb);
nfs_local_pgio_done(iocb->hdr, ret);
nfs_local_read_done(iocb, ret);
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_read_aio_complete_work */
}
@@ -444,14 +596,25 @@ static void nfs_local_call_read(struct work_struct *work)
container_of(work, struct nfs_local_kiocb, work);
struct file *filp = iocb->kiocb.ki_filp;
const struct cred *save_cred;
struct iov_iter iter;
ssize_t status;
save_cred = override_creds(filp->f_cred);
nfs_local_iter_init(&iter, iocb, READ);
for (int i = 0; i < iocb->n_iters ; i++) {
if (iocb->iter_is_dio_aligned[i]) {
iocb->kiocb.ki_flags |= IOCB_DIRECT;
iocb->kiocb.ki_complete = nfs_local_read_aio_complete;
iocb->aio_complete_work = nfs_local_read_aio_complete_work;
}
status = filp->f_op->read_iter(&iocb->kiocb, &iter);
iocb->kiocb.ki_pos = iocb->offset[i];
status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]);
if (status != -EIOCBQUEUED) {
nfs_local_pgio_done(iocb->hdr, status);
if (iocb->hdr->task.tk_status)
break;
}
}
revert_creds(save_cred);
@@ -462,33 +625,17 @@ static void nfs_local_call_read(struct work_struct *work)
}
static int
nfs_do_local_read(struct nfs_pgio_header *hdr,
struct nfsd_file *localio,
nfs_local_do_read(struct nfs_local_kiocb *iocb,
const struct rpc_call_ops *call_ops)
{
struct nfs_local_kiocb *iocb;
struct file *file = nfs_to->nfsd_file_file(localio);
/* Don't support filesystems without read_iter */
if (!file->f_op->read_iter)
return -EAGAIN;
struct nfs_pgio_header *hdr = iocb->hdr;
dprintk("%s: vfs_read count=%u pos=%llu\n",
__func__, hdr->args.count, hdr->args.offset);
iocb = nfs_local_iocb_alloc(hdr, file, GFP_KERNEL);
if (iocb == NULL)
return -ENOMEM;
iocb->localio = localio;
nfs_local_pgio_init(hdr, call_ops);
hdr->res.eof = false;
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
iocb->kiocb.ki_complete = nfs_local_read_aio_complete;
iocb->aio_complete_work = nfs_local_read_aio_complete_work;
}
INIT_WORK(&iocb->work, nfs_local_call_read);
queue_work(nfslocaliod_workqueue, &iocb->work);
@@ -597,7 +744,13 @@ nfs_local_write_done(struct nfs_local_kiocb *iocb, long status)
dprintk("%s: wrote %ld bytes.\n", __func__, status > 0 ? status : 0);
if ((iocb->kiocb.ki_flags & IOCB_DIRECT) && status == -EINVAL) {
/* Underlying FS will return -EINVAL if misaligned DIO is attempted. */
pr_info_ratelimited("nfs: Unexpected direct I/O write alignment failure\n");
}
/* Handle short writes as if they are ENOSPC */
status = hdr->res.count;
if (status > 0 && status < hdr->args.count) {
hdr->mds_offset += status;
hdr->args.offset += status;
@@ -605,11 +758,11 @@ nfs_local_write_done(struct nfs_local_kiocb *iocb, long status)
hdr->args.count -= status;
nfs_set_pgio_error(hdr, -ENOSPC, hdr->args.offset);
status = -ENOSPC;
/* record -ENOSPC in terms of nfs_local_pgio_done */
nfs_local_pgio_done(hdr, status);
}
if (status < 0)
if (hdr->task.tk_status < 0)
nfs_reset_boot_verifier(inode);
nfs_local_pgio_done(hdr, status);
}
static void nfs_local_write_aio_complete_work(struct work_struct *work)
@@ -626,6 +779,7 @@ static void nfs_local_write_aio_complete(struct kiocb *kiocb, long ret)
struct nfs_local_kiocb *iocb =
container_of(kiocb, struct nfs_local_kiocb, kiocb);
nfs_local_pgio_done(iocb->hdr, ret);
nfs_local_write_done(iocb, ret);
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_write_aio_complete_work */
}
@@ -637,16 +791,53 @@ static void nfs_local_call_write(struct work_struct *work)
struct file *filp = iocb->kiocb.ki_filp;
unsigned long old_flags = current->flags;
const struct cred *save_cred;
struct iov_iter iter;
ssize_t status;
current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
save_cred = override_creds(filp->f_cred);
nfs_local_iter_init(&iter, iocb, WRITE);
file_start_write(filp);
status = filp->f_op->write_iter(&iocb->kiocb, &iter);
for (int i = 0; i < iocb->n_iters ; i++) {
if (iocb->iter_is_dio_aligned[i]) {
iocb->kiocb.ki_flags |= IOCB_DIRECT;
iocb->kiocb.ki_complete = nfs_local_write_aio_complete;
iocb->aio_complete_work = nfs_local_write_aio_complete_work;
}
retry:
iocb->kiocb.ki_pos = iocb->offset[i];
status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]);
if (status != -EIOCBQUEUED) {
if (unlikely(status >= 0 && status < iocb->iters[i].count)) {
/* partial write */
if (i == iocb->end_iter_index) {
/* Must not account partial end, otherwise, due
* to end being issued before middle: the partial
* write accounting in nfs_local_write_done()
* would incorrectly advance hdr->args.offset
*/
status = 0;
} else {
/* Partial write at start or buffered middle,
* exit early.
*/
nfs_local_pgio_done(iocb->hdr, status);
break;
}
} else if (unlikely(status == -ENOTBLK &&
(iocb->kiocb.ki_flags & IOCB_DIRECT))) {
/* VFS will return -ENOTBLK if DIO WRITE fails to
* invalidate the page cache. Retry using buffered IO.
*/
iocb->kiocb.ki_flags &= ~IOCB_DIRECT;
iocb->kiocb.ki_complete = NULL;
iocb->aio_complete_work = NULL;
goto retry;
}
nfs_local_pgio_done(iocb->hdr, status);
if (iocb->hdr->task.tk_status)
break;
}
}
file_end_write(filp);
revert_creds(save_cred);
@@ -660,26 +851,15 @@ static void nfs_local_call_write(struct work_struct *work)
}
static int
nfs_do_local_write(struct nfs_pgio_header *hdr,
struct nfsd_file *localio,
nfs_local_do_write(struct nfs_local_kiocb *iocb,
const struct rpc_call_ops *call_ops)
{
struct nfs_local_kiocb *iocb;
struct file *file = nfs_to->nfsd_file_file(localio);
/* Don't support filesystems without write_iter */
if (!file->f_op->write_iter)
return -EAGAIN;
struct nfs_pgio_header *hdr = iocb->hdr;
dprintk("%s: vfs_write count=%u pos=%llu %s\n",
__func__, hdr->args.count, hdr->args.offset,
(hdr->args.stable == NFS_UNSTABLE) ? "unstable" : "stable");
iocb = nfs_local_iocb_alloc(hdr, file, GFP_NOIO);
if (iocb == NULL)
return -ENOMEM;
iocb->localio = localio;
switch (hdr->args.stable) {
default:
break;
@@ -694,43 +874,74 @@ nfs_do_local_write(struct nfs_pgio_header *hdr,
nfs_set_local_verifier(hdr->inode, hdr->res.verf, hdr->args.stable);
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
iocb->kiocb.ki_complete = nfs_local_write_aio_complete;
iocb->aio_complete_work = nfs_local_write_aio_complete_work;
}
INIT_WORK(&iocb->work, nfs_local_call_write);
queue_work(nfslocaliod_workqueue, &iocb->work);
return 0;
}
static struct nfs_local_kiocb *
nfs_local_iocb_init(struct nfs_pgio_header *hdr, struct nfsd_file *localio)
{
struct file *file = nfs_to->nfsd_file_file(localio);
struct nfs_local_kiocb *iocb;
gfp_t gfp_mask;
int rw;
if (hdr->rw_mode & FMODE_READ) {
if (!file->f_op->read_iter)
return ERR_PTR(-EOPNOTSUPP);
gfp_mask = GFP_KERNEL;
rw = ITER_DEST;
} else {
if (!file->f_op->write_iter)
return ERR_PTR(-EOPNOTSUPP);
gfp_mask = GFP_NOIO;
rw = ITER_SOURCE;
}
iocb = nfs_local_iocb_alloc(hdr, file, gfp_mask);
if (iocb == NULL)
return ERR_PTR(-ENOMEM);
iocb->hdr = hdr;
iocb->localio = localio;
nfs_local_iters_init(iocb, rw);
return iocb;
}
int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
struct nfs_pgio_header *hdr,
const struct rpc_call_ops *call_ops)
{
struct nfs_local_kiocb *iocb;
int status = 0;
if (!hdr->args.count)
return 0;
iocb = nfs_local_iocb_init(hdr, localio);
if (IS_ERR(iocb))
return PTR_ERR(iocb);
switch (hdr->rw_mode) {
case FMODE_READ:
status = nfs_do_local_read(hdr, localio, call_ops);
status = nfs_local_do_read(iocb, call_ops);
break;
case FMODE_WRITE:
status = nfs_do_local_write(hdr, localio, call_ops);
status = nfs_local_do_write(iocb, call_ops);
break;
default:
dprintk("%s: invalid mode: %d\n", __func__,
hdr->rw_mode);
status = -EINVAL;
status = -EOPNOTSUPP;
}
if (status != 0) {
if (status == -EAGAIN)
nfs_localio_disable_client(clp);
nfs_local_file_put(localio);
nfs_local_iocb_release(iocb);
hdr->task.tk_status = status;
nfs_local_hdr_release(hdr, call_ops);
}

View File

@@ -23,8 +23,8 @@
#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_common.h>
#include "nfstrace.h"
#include "internal.h"
#include "nfstrace.h"
#define NFSDBG_FACILITY NFSDBG_XDR

View File

@@ -23,8 +23,8 @@
#include <linux/nfsacl.h>
#include <linux/nfs_common.h>
#include "nfstrace.h"
#include "internal.h"
#include "nfstrace.h"
#define NFSDBG_FACILITY NFSDBG_XDR

View File

@@ -1514,7 +1514,7 @@ static ssize_t _nfs42_proc_listxattrs(struct inode *inode, void *buf,
ret = -ENOMEM;
res.scratch = alloc_page(GFP_KERNEL);
res.scratch = folio_alloc(GFP_KERNEL, 0);
if (!res.scratch)
goto out;
@@ -1552,7 +1552,7 @@ out_free_pages:
}
kfree(pages);
out_free_scratch:
__free_page(res.scratch);
folio_put(res.scratch);
out:
return ret;

View File

@@ -1781,7 +1781,7 @@ static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp,
struct compound_hdr hdr;
int status;
xdr_set_scratch_page(xdr, res->scratch);
xdr_set_scratch_folio(xdr, res->scratch);
status = decode_compound_hdr(xdr, &hdr);
if (status)

View File

@@ -456,4 +456,5 @@ const struct file_operations nfs4_file_operations = {
#else
.llseek = nfs_file_llseek,
#endif
.fop_flags = FOP_DONTCACHE,
};

View File

@@ -391,7 +391,9 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
*p++ = htonl(attrs); /* bitmap */
*p++ = htonl(12); /* attribute buffer length */
*p++ = htonl(NF4DIR);
spin_lock(&dentry->d_lock);
p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent)));
spin_unlock(&dentry->d_lock);
readdir->pgbase = (char *)p - (char *)start;
readdir->count -= readdir->pgbase;
@@ -6160,7 +6162,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
}
/* for decoding across pages */
res.acl_scratch = alloc_page(GFP_KERNEL);
res.acl_scratch = folio_alloc(GFP_KERNEL, 0);
if (!res.acl_scratch)
goto out_free;
@@ -6196,7 +6198,7 @@ out_free:
while (--i >= 0)
__free_page(pages[i]);
if (res.acl_scratch)
__free_page(res.acl_scratch);
folio_put(res.acl_scratch);
kfree(pages);
return ret;
}
@@ -7872,10 +7874,10 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state,
return err;
do {
err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
if (err != -NFS4ERR_DELAY)
if (err != -NFS4ERR_DELAY && err != -NFS4ERR_GRACE)
break;
ssleep(1);
} while (err == -NFS4ERR_DELAY);
} while (err == -NFS4ERR_DELAY || err == -NFSERR_GRACE);
return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err);
}
@@ -9442,7 +9444,7 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args
goto out;
if (rcvd->max_rqst_sz > sent->max_rqst_sz)
return -EINVAL;
if (rcvd->max_resp_sz < sent->max_resp_sz)
if (rcvd->max_resp_sz > sent->max_resp_sz)
return -EINVAL;
if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
return -EINVAL;

View File

@@ -2744,6 +2744,9 @@ out_error:
case -ENETUNREACH:
nfs_mark_client_ready(clp, -EIO);
break;
case -EINVAL:
nfs_mark_client_ready(clp, status);
break;
default:
ssleep(1);
break;

View File

@@ -4930,7 +4930,7 @@ static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
}
/*
* The prefered block size for layout directed io
* The preferred block size for layout directed io
*/
static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
uint32_t *res)
@@ -6585,7 +6585,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
int status;
if (res->acl_scratch != NULL)
xdr_set_scratch_page(xdr, res->acl_scratch);
xdr_set_scratch_folio(xdr, res->acl_scratch);
status = decode_compound_hdr(xdr, &hdr);
if (status)
goto out;

View File

@@ -45,6 +45,23 @@
{ BIT(NFS_INO_LAYOUTSTATS), "LAYOUTSTATS" }, \
{ BIT(NFS_INO_ODIRECT), "ODIRECT" })
#define nfs_show_wb_flags(v) \
__print_flags(v, "|", \
{ BIT(PG_BUSY), "BUSY" }, \
{ BIT(PG_MAPPED), "MAPPED" }, \
{ BIT(PG_FOLIO), "FOLIO" }, \
{ BIT(PG_CLEAN), "CLEAN" }, \
{ BIT(PG_COMMIT_TO_DS), "COMMIT_TO_DS" }, \
{ BIT(PG_INODE_REF), "INODE_REF" }, \
{ BIT(PG_HEADLOCK), "HEADLOCK" }, \
{ BIT(PG_TEARDOWN), "TEARDOWN" }, \
{ BIT(PG_UNLOCKPAGE), "UNLOCKPAGE" }, \
{ BIT(PG_UPTODATE), "UPTODATE" }, \
{ BIT(PG_WB_END), "WB_END" }, \
{ BIT(PG_REMOVE), "REMOVE" }, \
{ BIT(PG_CONTENDED1), "CONTENDED1" }, \
{ BIT(PG_CONTENDED2), "CONTENDED2" })
DECLARE_EVENT_CLASS(nfs_inode_event,
TP_PROTO(
const struct inode *inode
@@ -967,7 +984,7 @@ DECLARE_EVENT_CLASS(nfs_folio_event,
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->version = inode_peek_iversion_raw(inode);
__entry->offset = offset,
__entry->offset = offset;
__entry->count = count;
),
@@ -1017,8 +1034,8 @@ DECLARE_EVENT_CLASS(nfs_folio_event_done,
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->version = inode_peek_iversion_raw(inode);
__entry->offset = offset,
__entry->count = count,
__entry->offset = offset;
__entry->count = count;
__entry->ret = ret;
),
@@ -1051,6 +1068,73 @@ DEFINE_NFS_FOLIO_EVENT_DONE(nfs_writeback_folio_done);
DEFINE_NFS_FOLIO_EVENT(nfs_invalidate_folio);
DEFINE_NFS_FOLIO_EVENT_DONE(nfs_launder_folio_done);
DEFINE_NFS_FOLIO_EVENT(nfs_try_to_update_request);
DEFINE_NFS_FOLIO_EVENT_DONE(nfs_try_to_update_request_done);
DEFINE_NFS_FOLIO_EVENT(nfs_update_folio);
DEFINE_NFS_FOLIO_EVENT_DONE(nfs_update_folio_done);
DEFINE_NFS_FOLIO_EVENT(nfs_write_begin);
DEFINE_NFS_FOLIO_EVENT_DONE(nfs_write_begin_done);
DEFINE_NFS_FOLIO_EVENT(nfs_write_end);
DEFINE_NFS_FOLIO_EVENT_DONE(nfs_write_end_done);
DEFINE_NFS_FOLIO_EVENT(nfs_writepages);
DEFINE_NFS_FOLIO_EVENT_DONE(nfs_writepages_done);
DECLARE_EVENT_CLASS(nfs_kiocb_event,
TP_PROTO(
const struct kiocb *iocb,
const struct iov_iter *iter
),
TP_ARGS(iocb, iter),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
__field(u64, version)
__field(loff_t, offset)
__field(size_t, count)
__field(int, flags)
),
TP_fast_assign(
const struct inode *inode = file_inode(iocb->ki_filp);
const struct nfs_inode *nfsi = NFS_I(inode);
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->version = inode_peek_iversion_raw(inode);
__entry->offset = iocb->ki_pos;
__entry->count = iov_iter_count(iter);
__entry->flags = iocb->ki_flags;
),
TP_printk(
"fileid=%02x:%02x:%llu fhandle=0x%08x version=%llu offset=%lld count=%zu ki_flags=%s",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle, __entry->version,
__entry->offset, __entry->count,
__print_flags(__entry->flags, "|", TRACE_IOCB_STRINGS)
)
);
#define DEFINE_NFS_KIOCB_EVENT(name) \
DEFINE_EVENT(nfs_kiocb_event, name, \
TP_PROTO( \
const struct kiocb *iocb, \
const struct iov_iter *iter \
), \
TP_ARGS(iocb, iter))
DEFINE_NFS_KIOCB_EVENT(nfs_file_read);
DEFINE_NFS_KIOCB_EVENT(nfs_file_write);
TRACE_EVENT(nfs_aop_readahead,
TP_PROTO(
const struct inode *inode,
@@ -1398,6 +1482,55 @@ TRACE_EVENT(nfs_writeback_done,
)
);
DECLARE_EVENT_CLASS(nfs_page_class,
TP_PROTO(
const struct nfs_page *req
),
TP_ARGS(req),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(u32, fhandle)
__field(u64, fileid)
__field(const struct nfs_page *__private, req)
__field(loff_t, offset)
__field(unsigned int, count)
__field(unsigned long, flags)
),
TP_fast_assign(
const struct inode *inode = folio_inode(req->wb_folio);
const struct nfs_inode *nfsi = NFS_I(inode);
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
__entry->req = req;
__entry->offset = req_offset(req);
__entry->count = req->wb_bytes;
__entry->flags = req->wb_flags;
),
TP_printk(
"fileid=%02x:%02x:%llu fhandle=0x%08x req=%p offset=%lld count=%u flags=%s",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid, __entry->fhandle,
__entry->req, __entry->offset, __entry->count,
nfs_show_wb_flags(__entry->flags)
)
);
#define DEFINE_NFS_PAGE_EVENT(name) \
DEFINE_EVENT(nfs_page_class, name, \
TP_PROTO( \
const struct nfs_page *req \
), \
TP_ARGS(req))
DEFINE_NFS_PAGE_EVENT(nfs_writepage_setup);
DEFINE_NFS_PAGE_EVENT(nfs_do_writepage);
DECLARE_EVENT_CLASS(nfs_page_error_class,
TP_PROTO(
const struct inode *inode,
@@ -1599,6 +1732,76 @@ DEFINE_NFS_DIRECT_REQ_EVENT(nfs_direct_write_completion);
DEFINE_NFS_DIRECT_REQ_EVENT(nfs_direct_write_schedule_iovec);
DEFINE_NFS_DIRECT_REQ_EVENT(nfs_direct_write_reschedule_io);
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
DECLARE_EVENT_CLASS(nfs_local_dio_class,
TP_PROTO(
const struct inode *inode,
loff_t offset,
ssize_t count,
const struct nfs_local_dio *local_dio
),
TP_ARGS(inode, offset, count, local_dio),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(u64, fileid)
__field(u32, fhandle)
__field(loff_t, offset)
__field(ssize_t, count)
__field(u32, mem_align)
__field(u32, offset_align)
__field(loff_t, start)
__field(ssize_t, start_len)
__field(loff_t, middle)
__field(ssize_t, middle_len)
__field(loff_t, end)
__field(ssize_t, end_len)
),
TP_fast_assign(
const struct nfs_inode *nfsi = NFS_I(inode);
const struct nfs_fh *fh = &nfsi->fh;
__entry->dev = inode->i_sb->s_dev;
__entry->fileid = nfsi->fileid;
__entry->fhandle = nfs_fhandle_hash(fh);
__entry->offset = offset;
__entry->count = count;
__entry->mem_align = local_dio->mem_align;
__entry->offset_align = local_dio->offset_align;
__entry->start = offset;
__entry->start_len = local_dio->start_len;
__entry->middle = local_dio->middle_offset;
__entry->middle_len = local_dio->middle_len;
__entry->end = local_dio->end_offset;
__entry->end_len = local_dio->end_len;
),
TP_printk("fileid=%02x:%02x:%llu fhandle=0x%08x "
"offset=%lld count=%zd "
"mem_align=%u offset_align=%u "
"start=%llu+%zd middle=%llu+%zd end=%llu+%zd",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->fileid,
__entry->fhandle, __entry->offset, __entry->count,
__entry->mem_align, __entry->offset_align,
__entry->start, __entry->start_len,
__entry->middle, __entry->middle_len,
__entry->end, __entry->end_len)
)
#define DEFINE_NFS_LOCAL_DIO_EVENT(name) \
DEFINE_EVENT(nfs_local_dio_class, nfs_local_dio_##name, \
TP_PROTO(const struct inode *inode, \
loff_t offset, \
ssize_t count, \
const struct nfs_local_dio *local_dio),\
TP_ARGS(inode, offset, count, local_dio))
DEFINE_NFS_LOCAL_DIO_EVENT(read);
DEFINE_NFS_LOCAL_DIO_EVENT(write);
DEFINE_NFS_LOCAL_DIO_EVENT(misaligned);
#endif /* CONFIG_NFS_LOCALIO */
TRACE_EVENT(nfs_fh_to_dentry,
TP_PROTO(
const struct super_block *sb,
@@ -1713,10 +1916,10 @@ TRACE_EVENT(nfs_local_open_fh,
),
TP_printk(
"error=%d fhandle=0x%08x mode=%s",
__entry->error,
"fhandle=0x%08x mode=%s result=%d",
__entry->fhandle,
show_fs_fmode_flags(__entry->fmode)
show_fs_fmode_flags(__entry->fmode),
__entry->error
)
);

View File

@@ -296,7 +296,7 @@ static void nfs_folio_end_writeback(struct folio *folio)
{
struct nfs_server *nfss = NFS_SERVER(folio->mapping->host);
folio_end_writeback(folio);
folio_end_writeback_no_dropbehind(folio);
if (atomic_long_dec_return(&nfss->writeback) <
NFS_CONGESTION_OFF_THRESH) {
nfss->write_congested = 0;
@@ -593,6 +593,7 @@ static int nfs_do_writepage(struct folio *folio, struct writeback_control *wbc,
if (IS_ERR(req))
return PTR_ERR(req);
trace_nfs_do_writepage(req);
nfs_folio_set_writeback(folio);
WARN_ON_ONCE(test_bit(PG_CLEAN, &req->wb_flags));
@@ -656,12 +657,14 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
int priority = 0;
int err;
trace_nfs_writepages(inode, wbc->range_start, wbc->range_end - wbc->range_start);
/* Wait with writeback until write congestion eases */
if (wbc->sync_mode == WB_SYNC_NONE && nfss->write_congested) {
err = wait_event_killable(nfss->write_congestion_wait,
nfss->write_congested == 0);
if (err)
return err;
goto out_err;
}
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
@@ -692,10 +695,10 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
} while (err < 0 && !nfs_error_is_fatal(err));
nfs_io_completion_put(ioc);
if (err < 0)
goto out_err;
return 0;
if (err > 0)
err = 0;
out_err:
trace_nfs_writepages_done(inode, wbc->range_start, wbc->range_end - wbc->range_start, err);
return err;
}
@@ -745,6 +748,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
clear_bit(PG_MAPPED, &req->wb_head->wb_flags);
}
spin_unlock(&mapping->i_private_lock);
folio_end_dropbehind(folio);
}
nfs_page_group_unlock(req);
@@ -926,7 +931,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
req->wb_nio = 0;
memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf));
nfs_mark_request_commit(req, hdr->lseg, &cinfo,
hdr->pgio_mirror_idx);
hdr->ds_commit_idx);
goto next;
}
remove_req:
@@ -1017,11 +1022,12 @@ static struct nfs_page *nfs_try_to_update_request(struct folio *folio,
unsigned int end;
int error;
trace_nfs_try_to_update_request(folio_inode(folio), offset, bytes);
end = offset + bytes;
req = nfs_lock_and_join_requests(folio);
if (IS_ERR_OR_NULL(req))
return req;
goto out;
rqend = req->wb_offset + req->wb_bytes;
/*
@@ -1043,6 +1049,9 @@ static struct nfs_page *nfs_try_to_update_request(struct folio *folio,
else
req->wb_bytes = rqend - req->wb_offset;
req->wb_nio = 0;
out:
trace_nfs_try_to_update_request_done(folio_inode(folio), offset, bytes,
PTR_ERR_OR_ZERO(req));
return req;
out_flushme:
/*
@@ -1053,6 +1062,7 @@ out_flushme:
nfs_mark_request_dirty(req);
nfs_unlock_and_release_request(req);
error = nfs_wb_folio(folio->mapping->host, folio);
trace_nfs_try_to_update_request_done(folio_inode(folio), offset, bytes, error);
return (error < 0) ? ERR_PTR(error) : NULL;
}
@@ -1090,6 +1100,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx,
req = nfs_setup_write_request(ctx, folio, offset, count);
if (IS_ERR(req))
return PTR_ERR(req);
trace_nfs_writepage_setup(req);
/* Update file length */
nfs_grow_file(folio, offset, count);
nfs_mark_uptodate(req);
@@ -1290,6 +1301,8 @@ int nfs_update_folio(struct file *file, struct folio *folio,
nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
trace_nfs_update_folio(inode, offset, count);
dprintk("NFS: nfs_update_folio(%pD2 %d@%lld)\n", file, count,
(long long)(folio_pos(folio) + offset));
@@ -1309,6 +1322,7 @@ int nfs_update_folio(struct file *file, struct folio *folio,
if (status < 0)
nfs_set_pageerror(mapping);
out:
trace_nfs_update_folio_done(inode, offset, count, status);
dprintk("NFS: nfs_update_folio returns %d (isize %lld)\n",
status, (long long)i_size_read(inode));
return status;
@@ -1806,7 +1820,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
nfs_mapping_set_error(folio, status);
nfs_inode_remove_request(req);
}
dprintk_cont(", error = %d\n", status);
dprintk(", error = %d\n", status);
goto next;
}
@@ -1816,11 +1830,11 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
/* We have a match */
if (folio)
nfs_inode_remove_request(req);
dprintk_cont(" OK\n");
dprintk(" OK\n");
goto next;
}
/* We have a mismatch. Write the page again */
dprintk_cont(" mismatch\n");
dprintk(" mismatch\n");
nfs_mark_request_dirty(req);
atomic_long_inc(&NFS_I(data->inode)->redirtied_pages);
next:

View File

@@ -231,6 +231,9 @@ nfsd_file_alloc(struct net *net, struct inode *inode, unsigned char need,
refcount_set(&nf->nf_ref, 1);
nf->nf_may = need;
nf->nf_mark = NULL;
nf->nf_dio_mem_align = 0;
nf->nf_dio_offset_align = 0;
nf->nf_dio_read_offset_align = 0;
return nf;
}
@@ -1069,6 +1072,35 @@ nfsd_file_is_cached(struct inode *inode)
return ret;
}
static __be32
nfsd_file_get_dio_attrs(const struct svc_fh *fhp, struct nfsd_file *nf)
{
struct inode *inode = file_inode(nf->nf_file);
struct kstat stat;
__be32 status;
/* Currently only need to get DIO alignment info for regular files */
if (!S_ISREG(inode->i_mode))
return nfs_ok;
status = fh_getattr(fhp, &stat);
if (status != nfs_ok)
return status;
trace_nfsd_file_get_dio_attrs(inode, &stat);
if (stat.result_mask & STATX_DIOALIGN) {
nf->nf_dio_mem_align = stat.dio_mem_align;
nf->nf_dio_offset_align = stat.dio_offset_align;
}
if (stat.result_mask & STATX_DIO_READ_ALIGN)
nf->nf_dio_read_offset_align = stat.dio_read_offset_align;
else
nf->nf_dio_read_offset_align = nf->nf_dio_offset_align;
return nfs_ok;
}
static __be32
nfsd_file_do_acquire(struct svc_rqst *rqstp, struct net *net,
struct svc_cred *cred,
@@ -1187,6 +1219,8 @@ open_file:
}
status = nfserrno(ret);
trace_nfsd_file_open(nf, status);
if (status == nfs_ok)
status = nfsd_file_get_dio_attrs(fhp, nf);
}
} else
status = nfserr_jukebox;

View File

@@ -54,6 +54,10 @@ struct nfsd_file {
struct list_head nf_gc;
struct rcu_head nf_rcu;
ktime_t nf_birthtime;
u32 nf_dio_mem_align;
u32 nf_dio_offset_align;
u32 nf_dio_read_offset_align;
};
int nfsd_file_cache_init(void);

View File

@@ -117,6 +117,16 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
return localio;
}
static void nfsd_file_dio_alignment(struct nfsd_file *nf,
u32 *nf_dio_mem_align,
u32 *nf_dio_offset_align,
u32 *nf_dio_read_offset_align)
{
*nf_dio_mem_align = nf->nf_dio_mem_align;
*nf_dio_offset_align = nf->nf_dio_offset_align;
*nf_dio_read_offset_align = nf->nf_dio_read_offset_align;
}
static const struct nfsd_localio_operations nfsd_localio_ops = {
.nfsd_net_try_get = nfsd_net_try_get,
.nfsd_net_put = nfsd_net_put,
@@ -124,6 +134,7 @@ static const struct nfsd_localio_operations nfsd_localio_ops = {
.nfsd_file_put_local = nfsd_file_put_local,
.nfsd_file_get_local = nfsd_file_get_local,
.nfsd_file_file = nfsd_file_file,
.nfsd_file_dio_alignment = nfsd_file_dio_alignment,
};
void nfsd_localio_ops_init(void)

View File

@@ -1954,7 +1954,7 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
* remaining listeners and recreate the list.
*/
if (delete)
svc_xprt_destroy_all(serv, net);
svc_xprt_destroy_all(serv, net, false);
/* walk list of addrs again, open any that still don't exist */
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_SOCK_ADDR, info->nlhdr,

View File

@@ -535,16 +535,13 @@ void nfsd_destroy_serv(struct net *net)
#endif
}
svc_xprt_destroy_all(serv, net);
/*
* write_ports can create the server without actually starting
* any threads--if we get shut down before any threads are
* any threads. If we get shut down before any threads are
* started, then nfsd_destroy_serv will be run before any of this
* other initialization has been done except the rpcb information.
*/
svc_rpcb_cleanup(serv, net);
svc_xprt_destroy_all(serv, net, true);
nfsd_shutdown_net(net);
svc_destroy(&serv);
}

View File

@@ -1133,6 +1133,33 @@ TRACE_EVENT(nfsd_file_alloc,
)
);
TRACE_EVENT(nfsd_file_get_dio_attrs,
TP_PROTO(
const struct inode *inode,
const struct kstat *stat
),
TP_ARGS(inode, stat),
TP_STRUCT__entry(
__field(const void *, inode)
__field(unsigned long, mask)
__field(u32, mem_align)
__field(u32, offset_align)
__field(u32, read_offset_align)
),
TP_fast_assign(
__entry->inode = inode;
__entry->mask = stat->result_mask;
__entry->mem_align = stat->dio_mem_align;
__entry->offset_align = stat->dio_offset_align;
__entry->read_offset_align = stat->dio_read_offset_align;
),
TP_printk("inode=%p flags=%s mem_align=%u offset_align=%u read_offset_align=%u",
__entry->inode, show_statx_mask(__entry->mask),
__entry->mem_align, __entry->offset_align,
__entry->read_offset_align
)
);
TRACE_EVENT(nfsd_file_acquire,
TP_PROTO(
const struct svc_rqst *rqstp,

View File

@@ -185,6 +185,10 @@ static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat)
u32 request_mask = STATX_BASIC_STATS;
struct path p = {.mnt = fh->fh_export->ex_path.mnt,
.dentry = fh->fh_dentry};
struct inode *inode = d_inode(p.dentry);
if (S_ISREG(inode->i_mode))
request_mask |= (STATX_DIOALIGN | STATX_DIO_READ_ALIGN);
if (fh->fh_maxsize == NFS4_FHSIZE)
request_mask |= (STATX_BTIME | STATX_CHANGE_COOKIE);

View File

@@ -122,8 +122,6 @@ struct nfs_pageio_descriptor {
/* arbitrarily selected limit to number of mirrors */
#define NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX 16
#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
extern struct nfs_page *nfs_page_create_from_page(struct nfs_open_context *ctx,
struct page *page,
unsigned int pgbase,

View File

@@ -862,7 +862,7 @@ struct nfs_getaclres {
size_t acl_len;
size_t acl_data_offset;
int acl_flags;
struct page * acl_scratch;
struct folio * acl_scratch;
};
struct nfs_setattrres {
@@ -1596,7 +1596,7 @@ struct nfs42_listxattrsargs {
struct nfs42_listxattrsres {
struct nfs4_sequence_res seq_res;
struct page *scratch;
struct folio *scratch;
void *xattr_buf;
size_t xattr_len;
u64 cookie;

View File

@@ -65,6 +65,8 @@ struct nfsd_localio_operations {
struct net *(*nfsd_file_put_local)(struct nfsd_file __rcu **);
struct nfsd_file *(*nfsd_file_get_local)(struct nfsd_file *);
struct file *(*nfsd_file_file)(struct nfsd_file *);
void (*nfsd_file_dio_alignment)(struct nfsd_file *,
u32 *, u32 *, u32 *);
} ____cacheline_aligned;
extern void nfsd_localio_ops_init(void);

View File

@@ -1229,6 +1229,8 @@ void folio_wait_writeback(struct folio *folio);
int folio_wait_writeback_killable(struct folio *folio);
void end_page_writeback(struct page *page);
void folio_end_writeback(struct folio *folio);
void folio_end_writeback_no_dropbehind(struct folio *folio);
void folio_end_dropbehind(struct folio *folio);
void folio_wait_stable(struct folio *folio);
void __folio_mark_dirty(struct folio *folio, struct address_space *, int warn);
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb);

View File

@@ -23,43 +23,30 @@ extern unsigned int nlm_debug;
#define dprintk(fmt, ...) \
dfprintk(FACILITY, fmt, ##__VA_ARGS__)
#define dprintk_cont(fmt, ...) \
dfprintk_cont(FACILITY, fmt, ##__VA_ARGS__)
#define dprintk_rcu(fmt, ...) \
dfprintk_rcu(FACILITY, fmt, ##__VA_ARGS__)
#define dprintk_rcu_cont(fmt, ...) \
dfprintk_rcu_cont(FACILITY, fmt, ##__VA_ARGS__)
#undef ifdebug
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac))
# if IS_ENABLED(CONFIG_SUNRPC_DEBUG_TRACE)
# define __sunrpc_printk(fmt, ...) trace_printk(fmt, ##__VA_ARGS__)
# else
# define __sunrpc_printk(fmt, ...) printk(KERN_DEFAULT fmt, ##__VA_ARGS__)
# endif
# define dfprintk(fac, fmt, ...) \
do { \
ifdebug(fac) \
printk(KERN_DEFAULT fmt, ##__VA_ARGS__); \
} while (0)
# define dfprintk_cont(fac, fmt, ...) \
do { \
ifdebug(fac) \
printk(KERN_CONT fmt, ##__VA_ARGS__); \
__sunrpc_printk(fmt, ##__VA_ARGS__); \
} while (0)
# define dfprintk_rcu(fac, fmt, ...) \
do { \
ifdebug(fac) { \
rcu_read_lock(); \
printk(KERN_DEFAULT fmt, ##__VA_ARGS__); \
rcu_read_unlock(); \
} \
} while (0)
# define dfprintk_rcu_cont(fac, fmt, ...) \
do { \
ifdebug(fac) { \
rcu_read_lock(); \
printk(KERN_CONT fmt, ##__VA_ARGS__); \
__sunrpc_printk(fmt, ##__VA_ARGS__); \
rcu_read_unlock(); \
} \
} while (0)
@@ -68,7 +55,6 @@ do { \
#else
# define ifdebug(fac) if (0)
# define dfprintk(fac, fmt, ...) do {} while (0)
# define dfprintk_cont(fac, fmt, ...) do {} while (0)
# define dfprintk_rcu(fac, fmt, ...) do {} while (0)
# define RPC_IFDEBUG(x)
#endif

View File

@@ -196,7 +196,7 @@ struct svc_rqst {
struct xdr_buf rq_arg;
struct xdr_stream rq_arg_stream;
struct xdr_stream rq_res_stream;
struct page *rq_scratch_page;
struct folio *rq_scratch_folio;
struct xdr_buf rq_res;
unsigned long rq_maxpages; /* num of entries in rq_pages */
struct page * *rq_pages;
@@ -503,7 +503,7 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
xdr_init_decode(xdr, buf, argv->iov_base, NULL);
xdr_set_scratch_page(xdr, rqstp->rq_scratch_page);
xdr_set_scratch_folio(xdr, rqstp->rq_scratch_folio);
}
/**

View File

@@ -165,7 +165,8 @@ int svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
struct net *net, const int family,
const unsigned short port, int flags,
const struct cred *cred);
void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net);
void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net,
bool unregister);
void svc_xprt_received(struct svc_xprt *xprt);
void svc_xprt_enqueue(struct svc_xprt *xprt);
void svc_xprt_put(struct svc_xprt *xprt);

View File

@@ -288,16 +288,16 @@ xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
}
/**
* xdr_set_scratch_page - Attach a scratch buffer for decoding data
* xdr_set_scratch_folio - Attach a scratch buffer for decoding data
* @xdr: pointer to xdr_stream struct
* @page: an anonymous page
* @page: an anonymous folio
*
* See xdr_set_scratch_buffer().
*/
static inline void
xdr_set_scratch_page(struct xdr_stream *xdr, struct page *page)
xdr_set_scratch_folio(struct xdr_stream *xdr, struct folio *folio)
{
xdr_set_scratch_buffer(xdr, page_address(page), PAGE_SIZE);
xdr_set_scratch_buffer(xdr, folio_address(folio), folio_size(folio));
}
/**

View File

@@ -141,3 +141,25 @@
{ ATTR_TIMES_SET, "TIMES_SET" }, \
{ ATTR_TOUCH, "TOUCH"}, \
{ ATTR_DELEG, "DELEG"})
#define show_statx_mask(flags) \
__print_flags(flags, "|", \
{ STATX_TYPE, "TYPE" }, \
{ STATX_MODE, "MODE" }, \
{ STATX_NLINK, "NLINK" }, \
{ STATX_UID, "UID" }, \
{ STATX_GID, "GID" }, \
{ STATX_ATIME, "ATIME" }, \
{ STATX_MTIME, "MTIME" }, \
{ STATX_CTIME, "CTIME" }, \
{ STATX_INO, "INO" }, \
{ STATX_SIZE, "SIZE" }, \
{ STATX_BLOCKS, "BLOCKS" }, \
{ STATX_BASIC_STATS, "BASIC_STATS" }, \
{ STATX_BTIME, "BTIME" }, \
{ STATX_MNT_ID, "MNT_ID" }, \
{ STATX_DIOALIGN, "DIOALIGN" }, \
{ STATX_MNT_ID_UNIQUE, "MNT_ID_UNIQUE" }, \
{ STATX_SUBVOL, "SUBVOL" }, \
{ STATX_WRITE_ATOMIC, "WRITE_ATOMIC" }, \
{ STATX_DIO_READ_ALIGN, "DIO_READ_ALIGN" })

View File

@@ -1621,7 +1621,7 @@ static void filemap_end_dropbehind(struct folio *folio)
* completes. Do that now. If we fail, it's likely because of a big folio -
* just reset dropbehind for that case and latter completions should invalidate.
*/
static void filemap_end_dropbehind_write(struct folio *folio)
void folio_end_dropbehind(struct folio *folio)
{
if (!folio_test_dropbehind(folio))
return;
@@ -1638,16 +1638,18 @@ static void filemap_end_dropbehind_write(struct folio *folio)
folio_unlock(folio);
}
}
EXPORT_SYMBOL_GPL(folio_end_dropbehind);
/**
* folio_end_writeback - End writeback against a folio.
* folio_end_writeback_no_dropbehind - End writeback against a folio.
* @folio: The folio.
*
* The folio must actually be under writeback.
* This call is intended for filesystems that need to defer dropbehind.
*
* Context: May be called from process or interrupt context.
*/
void folio_end_writeback(struct folio *folio)
void folio_end_writeback_no_dropbehind(struct folio *folio)
{
VM_BUG_ON_FOLIO(!folio_test_writeback(folio), folio);
@@ -1663,6 +1665,25 @@ void folio_end_writeback(struct folio *folio)
folio_rotate_reclaimable(folio);
}
if (__folio_end_writeback(folio))
folio_wake_bit(folio, PG_writeback);
acct_reclaim_writeback(folio);
}
EXPORT_SYMBOL_GPL(folio_end_writeback_no_dropbehind);
/**
* folio_end_writeback - End writeback against a folio.
* @folio: The folio.
*
* The folio must actually be under writeback.
*
* Context: May be called from process or interrupt context.
*/
void folio_end_writeback(struct folio *folio)
{
VM_BUG_ON_FOLIO(!folio_test_writeback(folio), folio);
/*
* Writeback does not hold a folio reference of its own, relying
* on truncation to wait for the clearing of PG_writeback.
@@ -1670,11 +1691,8 @@ void folio_end_writeback(struct folio *folio)
* reused before the folio_wake_bit().
*/
folio_get(folio);
if (__folio_end_writeback(folio))
folio_wake_bit(folio, PG_writeback);
filemap_end_dropbehind_write(folio);
acct_reclaim_writeback(folio);
folio_end_writeback_no_dropbehind(folio);
folio_end_dropbehind(folio);
folio_put(folio);
}
EXPORT_SYMBOL(folio_end_writeback);

View File

@@ -101,6 +101,20 @@ config SUNRPC_DEBUG
If unsure, say Y.
config SUNRPC_DEBUG_TRACE
bool "RPC: Send dfprintk() output to the trace buffer"
depends on SUNRPC_DEBUG && TRACING
default n
help
dprintk() output can be voluminous, which can overwhelm the
kernel's logging facility as it must be sent to the console.
This option causes dprintk() output to go to the trace buffer
instead of the kernel log.
This will cause warnings about trace_printk() being used to be
logged at boot time, so say N unless you are debugging a problem
with sunrpc-based clients or services.
config SUNRPC_XPRT_RDMA
tristate "RPC-over-RDMA transport"
depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS

View File

@@ -794,12 +794,12 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
struct gssx_res_accept_sec_context *res = data;
u32 value_follows;
int err;
struct page *scratch;
struct folio *scratch;
scratch = alloc_page(GFP_KERNEL);
scratch = folio_alloc(GFP_KERNEL, 0);
if (!scratch)
return -ENOMEM;
xdr_set_scratch_page(xdr, scratch);
xdr_set_scratch_folio(xdr, scratch);
/* res->status */
err = gssx_dec_status(xdr, &res->status);
@@ -844,6 +844,6 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
err = gssx_dec_option_array(xdr, &res->options);
out_free:
__free_page(scratch);
folio_put(scratch);
return err;
}

View File

@@ -1074,7 +1074,6 @@ int rpc_malloc(struct rpc_task *task)
rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize;
return 0;
}
EXPORT_SYMBOL_GPL(rpc_malloc);
/**
* rpc_free - free RPC buffer resources allocated via rpc_malloc
@@ -1095,7 +1094,6 @@ void rpc_free(struct rpc_task *task)
else
kfree(buf);
}
EXPORT_SYMBOL_GPL(rpc_free);
/*
* Creation and deletion of RPC task structures

View File

@@ -86,7 +86,7 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, struct xdr_skb_reader *desc)
/* ACL likes to be lazy in allocating pages - ACLs
* are small by default but can get huge. */
if ((xdr->flags & XDRBUF_SPARSE_PAGES) && *ppage == NULL) {
*ppage = alloc_page(GFP_NOWAIT | __GFP_NOWARN);
*ppage = alloc_page(GFP_NOWAIT);
if (unlikely(*ppage == NULL)) {
if (copied == 0)
return -ENOMEM;

View File

@@ -352,7 +352,7 @@ static int svc_pool_map_get_node(unsigned int pidx)
if (m->mode == SVC_POOL_PERNODE)
return m->pool_to[pidx];
}
return NUMA_NO_NODE;
return numa_mem_id();
}
/*
* Set the given thread's cpus_allowed mask so that it
@@ -436,7 +436,6 @@ void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
svc_unregister(serv, net);
rpcb_put_local(net);
}
EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
static int svc_uses_rpcbind(struct svc_serv *serv)
{
@@ -670,8 +669,8 @@ svc_rqst_free(struct svc_rqst *rqstp)
folio_batch_release(&rqstp->rq_fbatch);
kfree(rqstp->rq_bvec);
svc_release_buffer(rqstp);
if (rqstp->rq_scratch_page)
put_page(rqstp->rq_scratch_page);
if (rqstp->rq_scratch_folio)
folio_put(rqstp->rq_scratch_folio);
kfree(rqstp->rq_resp);
kfree(rqstp->rq_argp);
kfree(rqstp->rq_auth_data);
@@ -692,8 +691,8 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
rqstp->rq_server = serv;
rqstp->rq_pool = pool;
rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0);
if (!rqstp->rq_scratch_page)
rqstp->rq_scratch_folio = __folio_alloc_node(GFP_KERNEL, 0, node);
if (!rqstp->rq_scratch_folio)
goto out_enomem;
rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);

View File

@@ -1102,6 +1102,7 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net)
* svc_xprt_destroy_all - Destroy transports associated with @serv
* @serv: RPC service to be shut down
* @net: target network namespace
* @unregister: true if it is OK to unregister the destroyed xprts
*
* Server threads may still be running (especially in the case where the
* service is still running in other network namespaces).
@@ -1114,7 +1115,8 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net)
* threads, we may need to wait a little while and then check again to
* see if they're done.
*/
void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net)
void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net,
bool unregister)
{
int delay = 0;
@@ -1124,6 +1126,9 @@ void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net)
svc_clean_up_xprts(serv, net);
msleep(delay++);
}
if (unregister)
svc_rpcb_cleanup(serv, net);
}
EXPORT_SYMBOL_GPL(svc_xprt_destroy_all);

View File

@@ -190,7 +190,7 @@ rpcrdma_alloc_sparse_pages(struct xdr_buf *buf)
ppages = buf->pages + (buf->page_base >> PAGE_SHIFT);
while (len > 0) {
if (!*ppages)
*ppages = alloc_page(GFP_NOWAIT | __GFP_NOWARN);
*ppages = alloc_page(GFP_NOWAIT);
if (!*ppages)
return -ENOBUFS;
ppages++;