Skip to content

Commit baf67f6

Browse files
committed
Merge tag 'nfs-for-6.13-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Bugfixes: - nfs/localio: fix for a memory corruption in nfs_local_read_done - Revert "nfs: don't reuse partially completed requests in nfs_lock_and_join_requests" - nfsv4: - ignore SB_RDONLY when mounting nfs - Fix a use-after-free problem in open() - sunrpc: - clear XPRT_SOCK_UPD_TIMEOUT when reseting the transport - timeout and cancel TLS handshake with -ETIMEDOUT - fix one UAF issue caused by sunrpc kernel tcp socket - Fix a hang in TLS sock_close if sk_write_pending - pNFS/blocklayout: Fix device registration issues Features and cleanups: - localio cleanups from Mike Snitzer - Clean up refcounting on the nfs version modules - __counted_by() annotations - nfs: make processes that are waiting for an I/O lock killable" * tag 'nfs-for-6.13-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (24 commits) fs/nfs/io: make nfs_start_io_*() killable nfs/blocklayout: Limit repeat device registration on failure nfs/blocklayout: Don't attempt unregister for invalid block device sunrpc: fix one UAF issue caused by sunrpc kernel tcp socket SUNRPC: timeout and cancel TLS handshake with -ETIMEDOUT sunrpc: clear XPRT_SOCK_UPD_TIMEOUT when reset transport nfs: ignore SB_RDONLY when mounting nfs Revert "nfs: don't reuse partially completed requests in nfs_lock_and_join_requests" Revert "fs: nfs: fix missing refcnt by replacing folio_set_private by folio_attach_private" nfs/localio: must clear res.replen in nfs_local_read_done NFSv4.0: Fix a use-after-free problem in the asynchronous open() NFSv4.0: Fix the wake up of the next waiter in nfs_release_seqid() SUNRPC: Fix a hang in TLS sock_close if sk_write_pending sunrpc: remove newlines from tracepoints nfs: Annotate struct pnfs_commit_array with __counted_by() nfs/localio: eliminate need for nfs_local_fsync_work forward declaration nfs/localio: remove extra indirect nfs_to call to check {read,write}_iter nfs/localio: eliminate unnecessary kref in nfs_local_fsync_ctx nfs/localio: remove redundant suid/sgid handling NFS: Implement get_nfs_version() ...
2 parents 0235da0 + 38a125b commit baf67f6

File tree

18 files changed

+229
-153
lines changed

18 files changed

+229
-153
lines changed

fs/nfs/blocklayout/blocklayout.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,19 +571,32 @@ bl_find_get_deviceid(struct nfs_server *server,
571571
if (!node)
572572
return ERR_PTR(-ENODEV);
573573

574+
/*
575+
* Devices that are marked unavailable are left in the cache with a
576+
* timeout to avoid sending GETDEVINFO after every LAYOUTGET, or
577+
* constantly attempting to register the device. Once marked as
578+
* unavailable they must be deleted and never reused.
579+
*/
574580
if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
575581
unsigned long end = jiffies;
576582
unsigned long start = end - PNFS_DEVICE_RETRY_TIMEOUT;
577583

578584
if (!time_in_range(node->timestamp_unavailable, start, end)) {
585+
/* Uncork subsequent GETDEVINFO operations for this device */
579586
nfs4_delete_deviceid(node->ld, node->nfs_client, id);
580587
goto retry;
581588
}
582589
goto out_put;
583590
}
584591

585-
if (!bl_register_dev(container_of(node, struct pnfs_block_dev, node)))
592+
if (!bl_register_dev(container_of(node, struct pnfs_block_dev, node))) {
593+
/*
594+
* If we cannot register, treat this device as transient:
595+
* Make a negative cache entry for the device
596+
*/
597+
nfs4_mark_deviceid_unavailable(node);
586598
goto out_put;
599+
}
587600

588601
return node;
589602

fs/nfs/blocklayout/dev.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ static void bl_unregister_scsi(struct pnfs_block_dev *dev)
2020
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
2121
int status;
2222

23-
if (!test_and_clear_bit(PNFS_BDEV_REGISTERED, &dev->flags))
24-
return;
25-
2623
status = ops->pr_register(bdev, dev->pr_key, 0, false);
2724
if (status)
2825
trace_bl_pr_key_unreg_err(bdev, dev->pr_key, status);
@@ -58,7 +55,8 @@ static void bl_unregister_dev(struct pnfs_block_dev *dev)
5855
return;
5956
}
6057

61-
if (dev->type == PNFS_BLOCK_VOLUME_SCSI)
58+
if (dev->type == PNFS_BLOCK_VOLUME_SCSI &&
59+
test_and_clear_bit(PNFS_BDEV_REGISTERED, &dev->flags))
6260
bl_unregister_scsi(dev);
6361
}
6462

fs/nfs/client.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,13 @@
5555
#define NFSDBG_FACILITY NFSDBG_CLIENT
5656

5757
static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
58-
static DEFINE_SPINLOCK(nfs_version_lock);
59-
static DEFINE_MUTEX(nfs_version_mutex);
60-
static LIST_HEAD(nfs_versions);
58+
static DEFINE_RWLOCK(nfs_version_lock);
59+
60+
static struct nfs_subversion *nfs_version_mods[5] = {
61+
[2] = NULL,
62+
[3] = NULL,
63+
[4] = NULL,
64+
};
6165

6266
/*
6367
* RPC cruft for NFS
@@ -76,62 +80,62 @@ const struct rpc_program nfs_program = {
7680
.pipe_dir_name = NFS_PIPE_DIRNAME,
7781
};
7882

79-
static struct nfs_subversion *find_nfs_version(unsigned int version)
83+
static struct nfs_subversion *__find_nfs_version(unsigned int version)
8084
{
8185
struct nfs_subversion *nfs;
82-
spin_lock(&nfs_version_lock);
83-
84-
list_for_each_entry(nfs, &nfs_versions, list) {
85-
if (nfs->rpc_ops->version == version) {
86-
spin_unlock(&nfs_version_lock);
87-
return nfs;
88-
}
89-
}
9086

91-
spin_unlock(&nfs_version_lock);
92-
return ERR_PTR(-EPROTONOSUPPORT);
87+
read_lock(&nfs_version_lock);
88+
nfs = nfs_version_mods[version];
89+
read_unlock(&nfs_version_lock);
90+
return nfs;
9391
}
9492

95-
struct nfs_subversion *get_nfs_version(unsigned int version)
93+
struct nfs_subversion *find_nfs_version(unsigned int version)
9694
{
97-
struct nfs_subversion *nfs = find_nfs_version(version);
95+
struct nfs_subversion *nfs = __find_nfs_version(version);
9896

99-
if (IS_ERR(nfs)) {
100-
mutex_lock(&nfs_version_mutex);
101-
request_module("nfsv%d", version);
102-
nfs = find_nfs_version(version);
103-
mutex_unlock(&nfs_version_mutex);
104-
}
97+
if (!nfs && request_module("nfsv%d", version) == 0)
98+
nfs = __find_nfs_version(version);
10599

106-
if (!IS_ERR(nfs) && !try_module_get(nfs->owner))
100+
if (!nfs)
101+
return ERR_PTR(-EPROTONOSUPPORT);
102+
103+
if (!get_nfs_version(nfs))
107104
return ERR_PTR(-EAGAIN);
105+
108106
return nfs;
109107
}
110108

109+
int get_nfs_version(struct nfs_subversion *nfs)
110+
{
111+
return try_module_get(nfs->owner);
112+
}
113+
EXPORT_SYMBOL_GPL(get_nfs_version);
114+
111115
void put_nfs_version(struct nfs_subversion *nfs)
112116
{
113117
module_put(nfs->owner);
114118
}
115119

116120
void register_nfs_version(struct nfs_subversion *nfs)
117121
{
118-
spin_lock(&nfs_version_lock);
122+
write_lock(&nfs_version_lock);
119123

120-
list_add(&nfs->list, &nfs_versions);
124+
nfs_version_mods[nfs->rpc_ops->version] = nfs;
121125
nfs_version[nfs->rpc_ops->version] = nfs->rpc_vers;
122126

123-
spin_unlock(&nfs_version_lock);
127+
write_unlock(&nfs_version_lock);
124128
}
125129
EXPORT_SYMBOL_GPL(register_nfs_version);
126130

127131
void unregister_nfs_version(struct nfs_subversion *nfs)
128132
{
129-
spin_lock(&nfs_version_lock);
133+
write_lock(&nfs_version_lock);
130134

131135
nfs_version[nfs->rpc_ops->version] = NULL;
132-
list_del(&nfs->list);
136+
nfs_version_mods[nfs->rpc_ops->version] = NULL;
133137

134-
spin_unlock(&nfs_version_lock);
138+
write_unlock(&nfs_version_lock);
135139
}
136140
EXPORT_SYMBOL_GPL(unregister_nfs_version);
137141

@@ -151,7 +155,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
151155

152156
clp->cl_minorversion = cl_init->minorversion;
153157
clp->cl_nfs_mod = cl_init->nfs_mod;
154-
if (!try_module_get(clp->cl_nfs_mod->owner))
158+
if (!get_nfs_version(clp->cl_nfs_mod))
155159
goto error_dealloc;
156160

157161
clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;

fs/nfs/direct.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
454454
if (user_backed_iter(iter))
455455
dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;
456456

457-
if (!swap)
458-
nfs_start_io_direct(inode);
457+
if (!swap) {
458+
result = nfs_start_io_direct(inode);
459+
if (result) {
460+
/* release the reference that would usually be
461+
* consumed by nfs_direct_read_schedule_iovec()
462+
*/
463+
nfs_direct_req_release(dreq);
464+
goto out_release;
465+
}
466+
}
459467

460468
NFS_I(inode)->read_io += count;
461469
requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
@@ -1007,7 +1015,14 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter,
10071015
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
10081016
FLUSH_STABLE);
10091017
} else {
1010-
nfs_start_io_direct(inode);
1018+
result = nfs_start_io_direct(inode);
1019+
if (result) {
1020+
/* release the reference that would usually be
1021+
* consumed by nfs_direct_write_schedule_iovec()
1022+
*/
1023+
nfs_direct_req_release(dreq);
1024+
goto out_release;
1025+
}
10111026

10121027
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
10131028
FLUSH_COND_STABLE);

fs/nfs/file.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
166166
iocb->ki_filp,
167167
iov_iter_count(to), (unsigned long) iocb->ki_pos);
168168

169-
nfs_start_io_read(inode);
169+
result = nfs_start_io_read(inode);
170+
if (result)
171+
return result;
172+
170173
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
171174
if (!result) {
172175
result = generic_file_read_iter(iocb, to);
@@ -187,7 +190,10 @@ nfs_file_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe
187190

188191
dprintk("NFS: splice_read(%pD2, %zu@%llu)\n", in, len, *ppos);
189192

190-
nfs_start_io_read(inode);
193+
result = nfs_start_io_read(inode);
194+
if (result)
195+
return result;
196+
191197
result = nfs_revalidate_mapping(inode, in->f_mapping);
192198
if (!result) {
193199
result = filemap_splice_read(in, ppos, pipe, len, flags);
@@ -668,7 +674,9 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
668674
nfs_clear_invalid_mapping(file->f_mapping);
669675

670676
since = filemap_sample_wb_err(file->f_mapping);
671-
nfs_start_io_write(inode);
677+
error = nfs_start_io_write(inode);
678+
if (error)
679+
return error;
672680
result = generic_write_checks(iocb, from);
673681
if (result > 0)
674682
result = generic_perform_write(iocb, from);

fs/nfs/fs_context.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,7 +1467,7 @@ static int nfs_fs_context_validate(struct fs_context *fc)
14671467

14681468
/* Load the NFS protocol module if we haven't done so yet */
14691469
if (!ctx->nfs_mod) {
1470-
nfs_mod = get_nfs_version(ctx->version);
1470+
nfs_mod = find_nfs_version(ctx->version);
14711471
if (IS_ERR(nfs_mod)) {
14721472
ret = PTR_ERR(nfs_mod);
14731473
goto out_version_unavailable;
@@ -1541,7 +1541,7 @@ static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
15411541
}
15421542
nfs_copy_fh(ctx->mntfh, src->mntfh);
15431543

1544-
__module_get(ctx->nfs_mod->owner);
1544+
get_nfs_version(ctx->nfs_mod);
15451545
ctx->client_address = NULL;
15461546
ctx->mount_server.hostname = NULL;
15471547
ctx->nfs_server.export_path = NULL;
@@ -1633,7 +1633,7 @@ static int nfs_init_fs_context(struct fs_context *fc)
16331633
}
16341634

16351635
ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod;
1636-
__module_get(ctx->nfs_mod->owner);
1636+
get_nfs_version(ctx->nfs_mod);
16371637
} else {
16381638
/* defaults */
16391639
ctx->timeo = NFS_UNSPEC_TIMEO;

fs/nfs/internal.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
#include "nfs4_fs.h"
77
#include <linux/fs_context.h>
88
#include <linux/security.h>
9+
#include <linux/compiler_attributes.h>
910
#include <linux/crc32.h>
1011
#include <linux/sunrpc/addr.h>
1112
#include <linux/nfs_page.h>
1213
#include <linux/nfslocalio.h>
1314
#include <linux/wait_bit.h>
1415

15-
#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
16+
#define NFS_SB_MASK (SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
1617

1718
extern const struct export_operations nfs_export_ops;
1819

@@ -516,11 +517,11 @@ extern const struct netfs_request_ops nfs_netfs_ops;
516517
#endif
517518

518519
/* io.c */
519-
extern void nfs_start_io_read(struct inode *inode);
520+
extern __must_check int nfs_start_io_read(struct inode *inode);
520521
extern void nfs_end_io_read(struct inode *inode);
521-
extern void nfs_start_io_write(struct inode *inode);
522+
extern __must_check int nfs_start_io_write(struct inode *inode);
522523
extern void nfs_end_io_write(struct inode *inode);
523-
extern void nfs_start_io_direct(struct inode *inode);
524+
extern __must_check int nfs_start_io_direct(struct inode *inode);
524525
extern void nfs_end_io_direct(struct inode *inode);
525526

526527
static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)

fs/nfs/io.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,28 @@ static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode)
3939
* Note that buffered writes and truncates both take a write lock on
4040
* inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
4141
*/
42-
void
42+
int
4343
nfs_start_io_read(struct inode *inode)
4444
{
4545
struct nfs_inode *nfsi = NFS_I(inode);
46+
int err;
47+
4648
/* Be an optimist! */
47-
down_read(&inode->i_rwsem);
49+
err = down_read_killable(&inode->i_rwsem);
50+
if (err)
51+
return err;
4852
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0)
49-
return;
53+
return 0;
5054
up_read(&inode->i_rwsem);
55+
5156
/* Slow path.... */
52-
down_write(&inode->i_rwsem);
57+
err = down_write_killable(&inode->i_rwsem);
58+
if (err)
59+
return err;
5360
nfs_block_o_direct(nfsi, inode);
5461
downgrade_write(&inode->i_rwsem);
62+
63+
return 0;
5564
}
5665

5766
/**
@@ -74,11 +83,15 @@ nfs_end_io_read(struct inode *inode)
7483
* Declare that a buffered read operation is about to start, and ensure
7584
* that we block all direct I/O.
7685
*/
77-
void
86+
int
7887
nfs_start_io_write(struct inode *inode)
7988
{
80-
down_write(&inode->i_rwsem);
81-
nfs_block_o_direct(NFS_I(inode), inode);
89+
int err;
90+
91+
err = down_write_killable(&inode->i_rwsem);
92+
if (!err)
93+
nfs_block_o_direct(NFS_I(inode), inode);
94+
return err;
8295
}
8396

8497
/**
@@ -119,19 +132,28 @@ static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode)
119132
* Note that buffered writes and truncates both take a write lock on
120133
* inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
121134
*/
122-
void
135+
int
123136
nfs_start_io_direct(struct inode *inode)
124137
{
125138
struct nfs_inode *nfsi = NFS_I(inode);
139+
int err;
140+
126141
/* Be an optimist! */
127-
down_read(&inode->i_rwsem);
142+
err = down_read_killable(&inode->i_rwsem);
143+
if (err)
144+
return err;
128145
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) != 0)
129-
return;
146+
return 0;
130147
up_read(&inode->i_rwsem);
148+
131149
/* Slow path.... */
132-
down_write(&inode->i_rwsem);
150+
err = down_write_killable(&inode->i_rwsem);
151+
if (err)
152+
return err;
133153
nfs_block_buffered(nfsi, inode);
134154
downgrade_write(&inode->i_rwsem);
155+
156+
return 0;
135157
}
136158

137159
/**

0 commit comments

Comments
 (0)