Skip to content

Commit

Permalink
Merge tag 'nfs-for-6.12-1' of git://git.linux-nfs.org/projects/anna/l…
Browse files Browse the repository at this point in the history
…inux-nfs

Pull NFS client updates from Anna Schumaker:
 "New Features:
   - Add a 'noalignwrite' mount option for lock-less 'lost writes' prevention
   - Add support for the LOCALIO protocol extention

  Bugfixes:
   - Fix memory leak in error path of nfs4_do_reclaim()
   - Simplify and guarantee lock owner uniqueness
   - Fix -Wformat-truncation warning
   - Fix folio refcounts by using folio_attach_private()
   - Fix failing the mount system call when the server is down
   - Fix detection of "Proxying of Times" server support

  Cleanups:
   - Annotate struct nfs_cache_array with __counted_by()
   - Remove unnecessary NULL checks before kfree()
   - Convert RPC_TASK_* constants to an enum
   - Remove obsolete or misleading comments and declerations"

* tag 'nfs-for-6.12-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (41 commits)
  nfs: Fix `make htmldocs` warnings in the localio documentation
  nfs: add "NFS Client and Server Interlock" section to localio.rst
  nfs: add FAQ section to Documentation/filesystems/nfs/localio.rst
  nfs: add Documentation/filesystems/nfs/localio.rst
  nfs: implement client support for NFS_LOCALIO_PROGRAM
  nfs/localio: use dedicated workqueues for filesystem read and write
  pnfs/flexfiles: enable localio support
  nfs: enable localio for non-pNFS IO
  nfs: add LOCALIO support
  nfs: pass struct nfsd_file to nfs_init_pgio and nfs_init_commit
  nfsd: implement server support for NFS_LOCALIO_PROGRAM
  nfsd: add LOCALIO support
  nfs_common: prepare for the NFS client to use nfsd_file for LOCALIO
  nfs_common: add NFS LOCALIO auxiliary protocol enablement
  SUNRPC: replace program list with program array
  SUNRPC: add svcauth_map_clnt_to_svc_cred_local
  SUNRPC: remove call_allocate() BUG_ONs
  nfsd: add nfsd_serv_try_get and nfsd_serv_put
  nfsd: add nfsd_file_acquire_local()
  nfsd: factor out __fh_verify to allow NULL rqstp to be passed
  ...
  • Loading branch information
torvalds committed Sep 24, 2024
2 parents f7fccaa + 6889813 commit 684a64b
Show file tree
Hide file tree
Showing 58 changed files with 2,519 additions and 464 deletions.
1 change: 1 addition & 0 deletions Documentation/filesystems/nfs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ NFS

client-identifier
exporting
localio
pnfs
rpc-cache
rpc-server-gss
Expand Down
357 changes: 357 additions & 0 deletions Documentation/filesystems/nfs/localio.rst

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,29 @@ config NFS_COMMON
depends on NFSD || NFS_FS || LOCKD
default y

config NFS_COMMON_LOCALIO_SUPPORT
tristate
default n
default y if NFSD=y || NFS_FS=y
default m if NFSD=m && NFS_FS=m
select SUNRPC

config NFS_LOCALIO
bool "NFS client and server support for LOCALIO auxiliary protocol"
depends on NFSD && NFS_FS
select NFS_COMMON_LOCALIO_SUPPORT
default n
help
Some NFS servers support an auxiliary NFS LOCALIO protocol
that is not an official part of the NFS protocol.

This option enables support for the LOCALIO protocol in the
kernel's NFS server and client. Enable this to permit local
NFS clients to bypass the network when issuing reads and
writes to the local NFS server.

If unsure, say N.

config NFS_V4_2_SSC_HELPER
bool
default y if NFS_V4_2
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config NFS_FS
depends on INET && FILE_LOCKING && MULTIUSER
select LOCKD
select SUNRPC
select NFS_COMMON
select NFS_ACL_SUPPORT if NFS_V3_ACL
help
Choose Y here if you want to access files residing on other
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o
nfs-$(CONFIG_NFS_LOCALIO) += localio.o

obj-$(CONFIG_NFS_V2) += nfsv2.o
nfsv2-y := nfs2super.o proc.o nfs2xdr.o
Expand Down
21 changes: 16 additions & 5 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
clp->cl_net = get_net(cl_init->net);

#if IS_ENABLED(CONFIG_NFS_LOCALIO)
seqlock_init(&clp->cl_boot_lock);
ktime_get_real_ts64(&clp->cl_nfssvc_boot);
clp->cl_uuid.net = NULL;
clp->cl_uuid.dom = NULL;
spin_lock_init(&clp->cl_localio_lock);
#endif /* CONFIG_NFS_LOCALIO */

clp->cl_principal = "*";
clp->cl_xprtsec = cl_init->xprtsec;
return clp;
Expand Down Expand Up @@ -233,6 +241,8 @@ static void pnfs_init_server(struct nfs_server *server)
*/
void nfs_free_client(struct nfs_client *clp)
{
nfs_local_disable(clp);

/* -EIO all pending I/O */
if (!IS_ERR(clp->cl_rpcclient))
rpc_shutdown_client(clp->cl_rpcclient);
Expand Down Expand Up @@ -424,7 +434,10 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
list_add_tail(&new->cl_share_link,
&nn->nfs_client_list);
spin_unlock(&nn->nfs_client_lock);
return rpc_ops->init_client(new, cl_init);
new = rpc_ops->init_client(new, cl_init);
if (!IS_ERR(new))
nfs_local_probe(new);
return new;
}

spin_unlock(&nn->nfs_client_lock);
Expand Down Expand Up @@ -997,8 +1010,8 @@ struct nfs_server *nfs_alloc_server(void)
init_waitqueue_head(&server->write_congestion_wait);
atomic_long_set(&server->writeback, 0);

ida_init(&server->openowner_id);
ida_init(&server->lockowner_id);
atomic64_set(&server->owner_ctr, 0);

pnfs_init_server(server);
rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");

Expand Down Expand Up @@ -1037,8 +1050,6 @@ void nfs_free_server(struct nfs_server *server)
}
ida_free(&s_sysfs_ids, server->s_sysfs_id);

ida_destroy(&server->lockowner_id);
ida_destroy(&server->openowner_id);
put_cred(server->cred);
nfs_release_automount_timer();
call_rcu(&server->rcu, delayed_free);
Expand Down
6 changes: 3 additions & 3 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ struct nfs_cache_array {
unsigned char folio_full : 1,
folio_is_eof : 1,
cookies_are_ordered : 1;
struct nfs_cache_array_entry array[];
struct nfs_cache_array_entry array[] __counted_by(size);
};

struct nfs_readdir_descriptor {
Expand Down Expand Up @@ -328,7 +328,8 @@ static int nfs_readdir_folio_array_append(struct folio *folio,
goto out;
}

cache_entry = &array->array[array->size];
array->size++;
cache_entry = &array->array[array->size - 1];
cache_entry->cookie = array->last_cookie;
cache_entry->ino = entry->ino;
cache_entry->d_type = entry->d_type;
Expand All @@ -337,7 +338,6 @@ static int nfs_readdir_folio_array_append(struct folio *folio,
array->last_cookie = entry->cookie;
if (array->last_cookie <= cache_entry->cookie)
array->cookies_are_ordered = 0;
array->size++;
if (entry->eof != 0)
nfs_readdir_array_set_eof(array);
out:
Expand Down
6 changes: 3 additions & 3 deletions fs/nfs/filelayout/filelayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ filelayout_read_pagelist(struct nfs_pgio_header *hdr)
/* Perform an asynchronous read to ds */
nfs_initiate_pgio(ds_clnt, hdr, hdr->cred,
NFS_PROTO(hdr->inode), &filelayout_read_call_ops,
0, RPC_TASK_SOFTCONN);
0, RPC_TASK_SOFTCONN, NULL);
return PNFS_ATTEMPTED;
}

Expand Down Expand Up @@ -530,7 +530,7 @@ filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
/* Perform an asynchronous write */
nfs_initiate_pgio(ds_clnt, hdr, hdr->cred,
NFS_PROTO(hdr->inode), &filelayout_write_call_ops,
sync, RPC_TASK_SOFTCONN);
sync, RPC_TASK_SOFTCONN, NULL);
return PNFS_ATTEMPTED;
}

Expand Down Expand Up @@ -1011,7 +1011,7 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
data->args.fh = fh;
return nfs_initiate_commit(ds_clnt, data, NFS_PROTO(data->inode),
&filelayout_commit_call_ops, how,
RPC_TASK_SOFTCONN);
RPC_TASK_SOFTCONN, NULL);
out_err:
pnfs_generic_prepare_to_resend_writes(data);
pnfs_generic_commit_release(data);
Expand Down
56 changes: 46 additions & 10 deletions fs/nfs/flexfilelayout/flexfilelayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/nfs_mount.h>
#include <linux/nfs_page.h>
#include <linux/module.h>
#include <linux/file.h>
#include <linux/sched/mm.h>

#include <linux/sunrpc/metrics.h>
Expand Down Expand Up @@ -162,6 +163,21 @@ decode_name(struct xdr_stream *xdr, u32 *id)
return 0;
}

static struct nfsd_file *
ff_local_open_fh(struct nfs_client *clp, const struct cred *cred,
struct nfs_fh *fh, fmode_t mode)
{
if (mode & FMODE_WRITE) {
/*
* Always request read and write access since this corresponds
* to a rw layout.
*/
mode |= FMODE_READ;
}

return nfs_local_open_fh(clp, cred, fh, mode);
}

static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1,
const struct nfs4_ff_layout_mirror *m2)
{
Expand Down Expand Up @@ -237,7 +253,7 @@ static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)

static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror)
{
const struct cred *cred;
const struct cred *cred;

ff_layout_remove_mirror(mirror);
kfree(mirror->fh_versions);
Expand Down Expand Up @@ -1756,6 +1772,7 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
struct pnfs_layout_segment *lseg = hdr->lseg;
struct nfs4_pnfs_ds *ds;
struct rpc_clnt *ds_clnt;
struct nfsd_file *localio;
struct nfs4_ff_layout_mirror *mirror;
const struct cred *ds_cred;
loff_t offset = hdr->args.offset;
Expand Down Expand Up @@ -1802,11 +1819,18 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
hdr->args.offset = offset;
hdr->mds_offset = offset;

/* Start IO accounting for local read */
localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh, FMODE_READ);
if (localio) {
hdr->task.tk_start = ktime_get();
ff_layout_read_record_layoutstats_start(&hdr->task, hdr);
}

/* Perform an asynchronous read to ds */
nfs_initiate_pgio(ds_clnt, hdr, ds_cred, ds->ds_clp->rpc_ops,
vers == 3 ? &ff_layout_read_call_ops_v3 :
&ff_layout_read_call_ops_v4,
0, RPC_TASK_SOFTCONN);
0, RPC_TASK_SOFTCONN, localio);
put_cred(ds_cred);
return PNFS_ATTEMPTED;

Expand All @@ -1826,6 +1850,7 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
struct pnfs_layout_segment *lseg = hdr->lseg;
struct nfs4_pnfs_ds *ds;
struct rpc_clnt *ds_clnt;
struct nfsd_file *localio;
struct nfs4_ff_layout_mirror *mirror;
const struct cred *ds_cred;
loff_t offset = hdr->args.offset;
Expand Down Expand Up @@ -1870,11 +1895,19 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
*/
hdr->args.offset = offset;

/* Start IO accounting for local write */
localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh,
FMODE_READ|FMODE_WRITE);
if (localio) {
hdr->task.tk_start = ktime_get();
ff_layout_write_record_layoutstats_start(&hdr->task, hdr);
}

/* Perform an asynchronous write */
nfs_initiate_pgio(ds_clnt, hdr, ds_cred, ds->ds_clp->rpc_ops,
vers == 3 ? &ff_layout_write_call_ops_v3 :
&ff_layout_write_call_ops_v4,
sync, RPC_TASK_SOFTCONN);
sync, RPC_TASK_SOFTCONN, localio);
put_cred(ds_cred);
return PNFS_ATTEMPTED;

Expand Down Expand Up @@ -1908,6 +1941,7 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
struct pnfs_layout_segment *lseg = data->lseg;
struct nfs4_pnfs_ds *ds;
struct rpc_clnt *ds_clnt;
struct nfsd_file *localio;
struct nfs4_ff_layout_mirror *mirror;
const struct cred *ds_cred;
u32 idx;
Expand Down Expand Up @@ -1946,10 +1980,18 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
if (fh)
data->args.fh = fh;

/* Start IO accounting for local commit */
localio = ff_local_open_fh(ds->ds_clp, ds_cred, fh,
FMODE_READ|FMODE_WRITE);
if (localio) {
data->task.tk_start = ktime_get();
ff_layout_commit_record_layoutstats_start(&data->task, data);
}

ret = nfs_initiate_commit(ds_clnt, data, ds->ds_clp->rpc_ops,
vers == 3 ? &ff_layout_commit_call_ops_v3 :
&ff_layout_commit_call_ops_v4,
how, RPC_TASK_SOFTCONN);
how, RPC_TASK_SOFTCONN, localio);
put_cred(ds_cred);
return ret;
out_err:
Expand Down Expand Up @@ -2086,12 +2128,6 @@ static int ff_layout_encode_ioerr(struct xdr_stream *xdr,
return ff_layout_encode_ds_ioerr(xdr, &ff_args->errors);
}

static void
encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
{
WARN_ON_ONCE(xdr_stream_encode_opaque_fixed(xdr, buf, len) < 0);
}

static void
ff_layout_encode_ff_iostat_head(struct xdr_stream *xdr,
const nfs4_stateid *stateid,
Expand Down
6 changes: 6 additions & 0 deletions fs/nfs/flexfilelayout/flexfilelayoutdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,12 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,

/* connect success, check rsize/wsize limit */
if (!status) {
/*
* ds_clp is put in destroy_ds().
* keep ds_clp even if DS is local, so that if local IO cannot
* proceed somehow, we can fall back to NFS whenever we want.
*/
nfs_local_probe(ds->ds_clp);
max_payload =
nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient),
NULL);
Expand Down
8 changes: 8 additions & 0 deletions fs/nfs/fs_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum nfs_param {
Opt_bsize,
Opt_clientaddr,
Opt_cto,
Opt_alignwrite,
Opt_fg,
Opt_fscache,
Opt_fscache_flag,
Expand Down Expand Up @@ -149,6 +150,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
fsparam_u32 ("bsize", Opt_bsize),
fsparam_string("clientaddr", Opt_clientaddr),
fsparam_flag_no("cto", Opt_cto),
fsparam_flag_no("alignwrite", Opt_alignwrite),
fsparam_flag ("fg", Opt_fg),
fsparam_flag_no("fsc", Opt_fscache_flag),
fsparam_string("fsc", Opt_fscache),
Expand Down Expand Up @@ -592,6 +594,12 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
else
ctx->flags |= NFS_MOUNT_TRUNK_DISCOVERY;
break;
case Opt_alignwrite:
if (result.negated)
ctx->flags |= NFS_MOUNT_NO_ALIGNWRITE;
else
ctx->flags &= ~NFS_MOUNT_NO_ALIGNWRITE;
break;
case Opt_ac:
if (result.negated)
ctx->flags |= NFS_MOUNT_NOAC;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/getroot.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
}

/*
* get an NFS2/NFS3 root dentry from the root filehandle
* get a root dentry from the root filehandle
*/
int nfs_get_root(struct super_block *s, struct fs_context *fc)
{
Expand Down
Loading

0 comments on commit 684a64b

Please sign in to comment.