Skip to content

Commit 6bb34af

Browse files
committed
Merge tag 'nfs-for-6.19-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Bugfixes: - Fix 'nlink' attribute update races when unlinking a file - Add missing initialisers for the directory verifier in various places - Don't regress the NFSv4 open state due to misordered racing replies - Ensure the NFSv4.x callback server uses the correct transport connection - Fix potential use-after-free races when shutting down the NFSv4.x callback server - Fix a pNFS layout commit crash - Assorted fixes to ensure correct propagation of mount options when the client crosses a filesystem boundary and triggers the VFS automount code - More localio fixes Features and cleanups: - Add initial support for basic directory delegations - SunRPC back channel code cleanups" * tag 'nfs-for-6.19-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (24 commits) NFSv4: Handle NFS4ERR_NOTSUPP errors for directory delegations nfs/localio: remove 61 byte hole from needless ____cacheline_aligned nfs/localio: remove alignment size checking in nfs_is_local_dio_possible NFS: Fix up the automount fs_context to use the correct cred NFS: Fix inheritance of the block sizes when automounting NFS: Automounted filesystems should inherit ro,noexec,nodev,sync flags Revert "nfs: ignore SB_RDONLY when mounting nfs" Revert "nfs: clear SB_RDONLY before getting superblock" Revert "nfs: ignore SB_RDONLY when remounting nfs" NFS: Add a module option to disable directory delegations NFS: Shortcut lookup revalidations if we have a directory delegation NFS: Request a directory delegation during RENAME NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK NFS: Add support for sending GDD_GETATTR NFSv4/pNFS: Clear NFS_INO_LAYOUTCOMMIT in pnfs_mark_layout_stateid_invalid NFSv4.1: protect destroying and nullifying bc_serv structure SUNRPC: new helper function for stopping backchannel server SUNRPC: cleanup common code in backchannel request NFSv4.1: pass transport for callback shutdown NFSv4: ensure the open stateid seqid doesn't go backwards ...
2 parents d358e52 + bd3b04b commit 6bb34af

25 files changed

Lines changed: 385 additions & 91 deletions

fs/nfs/callback.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
258258
/*
259259
* Kill the callback thread if it's no longer being used.
260260
*/
261-
void nfs_callback_down(int minorversion, struct net *net)
261+
void nfs_callback_down(int minorversion, struct net *net, struct rpc_xprt *xprt)
262262
{
263263
struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
264264
struct svc_serv *serv;
@@ -270,7 +270,7 @@ void nfs_callback_down(int minorversion, struct net *net)
270270
if (cb_info->users == 0) {
271271
svc_set_num_threads(serv, NULL, 0);
272272
dprintk("nfs_callback_down: service destroyed\n");
273-
svc_destroy(&cb_info->serv);
273+
xprt_svc_destroy_nullify_bc(xprt, &cb_info->serv);
274274
}
275275
mutex_unlock(&nfs_callback_mutex);
276276
}

fs/nfs/callback.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ extern __be32 nfs4_callback_recall(void *argp, void *resp,
188188
struct cb_process_state *cps);
189189
#if IS_ENABLED(CONFIG_NFS_V4)
190190
extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
191-
extern void nfs_callback_down(int minorversion, struct net *net);
191+
extern void nfs_callback_down(int minorversion, struct net *net,
192+
struct rpc_xprt *xprt);
192193
#endif /* CONFIG_NFS_V4 */
193194
/*
194195
* nfs41: Callbacks are expected to not cause substantial latency,

fs/nfs/client.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -784,10 +784,18 @@ static int nfs_init_server(struct nfs_server *server,
784784
server->fattr_valid = NFS_ATTR_FATTR_V4;
785785
}
786786

787-
if (ctx->rsize)
787+
if (ctx->bsize) {
788+
server->bsize = ctx->bsize;
789+
server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE;
790+
}
791+
if (ctx->rsize) {
788792
server->rsize = nfs_io_size(ctx->rsize, clp->cl_proto);
789-
if (ctx->wsize)
793+
server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE;
794+
}
795+
if (ctx->wsize) {
790796
server->wsize = nfs_io_size(ctx->wsize, clp->cl_proto);
797+
server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE;
798+
}
791799

792800
server->acregmin = ctx->acregmin * HZ;
793801
server->acregmax = ctx->acregmax * HZ;
@@ -977,8 +985,13 @@ EXPORT_SYMBOL_GPL(nfs_probe_server);
977985
void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
978986
{
979987
target->flags = source->flags;
980-
target->rsize = source->rsize;
981-
target->wsize = source->wsize;
988+
target->automount_inherit = source->automount_inherit;
989+
if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE)
990+
target->bsize = source->bsize;
991+
if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_RSIZE)
992+
target->rsize = source->rsize;
993+
if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_WSIZE)
994+
target->wsize = source->wsize;
982995
target->acregmin = source->acregmin;
983996
target->acregmax = source->acregmax;
984997
target->acdirmin = source->acdirmin;

fs/nfs/delegation.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
3131
module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
3232

33+
bool directory_delegations = true;
34+
module_param(directory_delegations, bool, 0644);
35+
MODULE_PARM_DESC(directory_delegations,
36+
"Enable the use of directory delegations, defaults to on.");
37+
3338
static struct hlist_head *nfs_delegation_hash(struct nfs_server *server,
3439
const struct nfs_fh *fhandle)
3540
{
@@ -143,6 +148,8 @@ static int nfs4_do_check_delegation(struct inode *inode, fmode_t type,
143148
*/
144149
int nfs4_have_delegation(struct inode *inode, fmode_t type, int flags)
145150
{
151+
if (S_ISDIR(inode->i_mode) && !directory_delegations)
152+
nfs_inode_evict_delegation(inode);
146153
return nfs4_do_check_delegation(inode, type, flags, true);
147154
}
148155

@@ -379,6 +386,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
379386
delegation->inode = NULL;
380387
rcu_assign_pointer(nfsi->delegation, NULL);
381388
spin_unlock(&delegation->lock);
389+
clear_bit(NFS_INO_REQ_DIR_DELEG, &nfsi->flags);
382390
return delegation;
383391
}
384392

fs/nfs/delegation.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,19 @@ static inline int nfs_have_delegated_mtime(struct inode *inode)
124124
NFS_DELEGATION_FLAG_TIME);
125125
}
126126

127+
extern bool directory_delegations;
128+
129+
static inline void nfs_request_directory_delegation(struct inode *inode)
130+
{
131+
if (S_ISDIR(inode->i_mode))
132+
set_bit(NFS_INO_REQ_DIR_DELEG, &NFS_I(inode)->flags);
133+
}
134+
135+
static inline bool nfs_have_directory_delegation(struct inode *inode)
136+
{
137+
return S_ISDIR(inode->i_mode) && nfs_have_delegated_attributes(inode);
138+
}
139+
127140
int nfs4_delegation_hash_alloc(struct nfs_server *server);
128141

129142
#endif

fs/nfs/dir.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -789,16 +789,17 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry,
789789
goto out;
790790
}
791791

792+
nfs_set_verifier(dentry, dir_verifier);
792793
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
793794
alias = d_splice_alias(inode, dentry);
794795
d_lookup_done(dentry);
795796
if (alias) {
796797
if (IS_ERR(alias))
797798
goto out;
799+
nfs_set_verifier(alias, dir_verifier);
798800
dput(dentry);
799801
dentry = alias;
800802
}
801-
nfs_set_verifier(dentry, dir_verifier);
802803
trace_nfs_readdir_lookup(d_inode(parent), dentry, 0);
803804
out:
804805
dput(dentry);
@@ -1514,6 +1515,15 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
15141515
return 0;
15151516
if (!nfs_dentry_verify_change(dir, dentry))
15161517
return 0;
1518+
1519+
/*
1520+
* If we have a directory delegation then we don't need to revalidate
1521+
* the directory. The delegation will either get recalled or we will
1522+
* receive a notification when it changes.
1523+
*/
1524+
if (nfs_have_directory_delegation(dir))
1525+
return 0;
1526+
15171527
/* Revalidate nfsi->cache_change_attribute before we declare a match */
15181528
if (nfs_mapping_need_revalidate_inode(dir)) {
15191529
if (rcu_walk)
@@ -1894,13 +1904,15 @@ static int nfs_dentry_delete(const struct dentry *dentry)
18941904
}
18951905

18961906
/* Ensure that we revalidate inode->i_nlink */
1897-
static void nfs_drop_nlink(struct inode *inode)
1907+
static void nfs_drop_nlink(struct inode *inode, unsigned long gencount)
18981908
{
1909+
struct nfs_inode *nfsi = NFS_I(inode);
1910+
18991911
spin_lock(&inode->i_lock);
19001912
/* drop the inode if we're reasonably sure this is the last link */
1901-
if (inode->i_nlink > 0)
1913+
if (inode->i_nlink > 0 && gencount == nfsi->attr_gencount)
19021914
drop_nlink(inode);
1903-
NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter();
1915+
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
19041916
nfs_set_cache_invalid(
19051917
inode, NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
19061918
NFS_INO_INVALID_NLINK);
@@ -1914,8 +1926,9 @@ static void nfs_drop_nlink(struct inode *inode)
19141926
static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
19151927
{
19161928
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
1929+
unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount);
19171930
nfs_complete_unlink(dentry, inode);
1918-
nfs_drop_nlink(inode);
1931+
nfs_drop_nlink(inode, gencount);
19191932
}
19201933
iput(inode);
19211934
}
@@ -1991,13 +2004,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
19912004
nfs_lookup_advise_force_readdirplus(dir, flags);
19922005

19932006
no_entry:
2007+
nfs_set_verifier(dentry, dir_verifier);
19942008
res = d_splice_alias(inode, dentry);
19952009
if (res != NULL) {
19962010
if (IS_ERR(res))
19972011
goto out;
2012+
nfs_set_verifier(res, dir_verifier);
19982013
dentry = res;
19992014
}
2000-
nfs_set_verifier(dentry, dir_verifier);
20012015
out:
20022016
trace_nfs_lookup_exit(dir, dentry, flags, PTR_ERR_OR_ZERO(res));
20032017
nfs_free_fattr(fattr);
@@ -2139,12 +2153,12 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
21392153
d_drop(dentry);
21402154
switch (err) {
21412155
case -ENOENT:
2142-
d_splice_alias(NULL, dentry);
21432156
if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
21442157
dir_verifier = inode_peek_iversion_raw(dir);
21452158
else
21462159
dir_verifier = nfs_save_change_attribute(dir);
21472160
nfs_set_verifier(dentry, dir_verifier);
2161+
d_splice_alias(NULL, dentry);
21482162
break;
21492163
case -EISDIR:
21502164
case -ENOTDIR:
@@ -2202,6 +2216,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
22022216
}
22032217
EXPORT_SYMBOL_GPL(nfs_atomic_open);
22042218

2219+
static int
2220+
nfs_lookup_revalidate_delegated_parent(struct inode *dir, struct dentry *dentry,
2221+
struct inode *inode)
2222+
{
2223+
return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
2224+
}
2225+
22052226
static int
22062227
nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name,
22072228
struct dentry *dentry, unsigned int flags)
@@ -2229,6 +2250,9 @@ nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name,
22292250
if (nfs_verifier_is_delegated(dentry))
22302251
return nfs_lookup_revalidate_delegated(dir, dentry, inode);
22312252

2253+
if (nfs_have_directory_delegation(dir))
2254+
return nfs_lookup_revalidate_delegated_parent(dir, dentry, inode);
2255+
22322256
/* NFS only supports OPEN on regular files */
22332257
if (!S_ISREG(inode->i_mode))
22342258
goto full_reval;
@@ -2507,9 +2531,11 @@ static int nfs_safe_remove(struct dentry *dentry)
25072531

25082532
trace_nfs_remove_enter(dir, dentry);
25092533
if (inode != NULL) {
2534+
unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount);
2535+
25102536
error = NFS_PROTO(dir)->remove(dir, dentry);
25112537
if (error == 0)
2512-
nfs_drop_nlink(inode);
2538+
nfs_drop_nlink(inode, gencount);
25132539
} else
25142540
error = NFS_PROTO(dir)->remove(dir, dentry);
25152541
if (error == -ENOENT)
@@ -2709,6 +2735,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27092735
{
27102736
struct inode *old_inode = d_inode(old_dentry);
27112737
struct inode *new_inode = d_inode(new_dentry);
2738+
unsigned long new_gencount = 0;
27122739
struct dentry *dentry = NULL;
27132740
struct rpc_task *task;
27142741
bool must_unblock = false;
@@ -2761,6 +2788,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27612788
} else {
27622789
block_revalidate(new_dentry);
27632790
must_unblock = true;
2791+
new_gencount = NFS_I(new_inode)->attr_gencount;
27642792
spin_unlock(&new_dentry->d_lock);
27652793
}
27662794

@@ -2800,7 +2828,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
28002828
new_dir, new_dentry, error);
28012829
if (!error) {
28022830
if (new_inode != NULL)
2803-
nfs_drop_nlink(new_inode);
2831+
nfs_drop_nlink(new_inode, new_gencount);
28042832
/*
28052833
* The d_move() should be here instead of in an async RPC completion
28062834
* handler because we need the proper locks to move the dentry. If

fs/nfs/inode.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
13891389
status = pnfs_sync_inode(inode, false);
13901390
if (status)
13911391
goto out;
1392+
} else if (nfs_have_directory_delegation(inode)) {
1393+
status = 0;
1394+
goto out;
13921395
}
13931396

13941397
status = -ENOMEM;

fs/nfs/internal.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <linux/nfslocalio.h>
1414
#include <linux/wait_bit.h>
1515

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

1818
extern const struct export_operations nfs_export_ops;
1919

@@ -152,7 +152,6 @@ struct nfs_fs_context {
152152
struct super_block *sb;
153153
struct dentry *dentry;
154154
struct nfs_fattr *fattr;
155-
unsigned int inherited_bsize;
156155
} clone_data;
157156
};
158157

fs/nfs/localio.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ struct nfs_local_kiocb {
4343
size_t end_len;
4444
short int end_iter_index;
4545
atomic_t n_iters;
46+
struct iov_iter iters[NFSLOCAL_MAX_IOS];
4647
bool iter_is_dio_aligned[NFSLOCAL_MAX_IOS];
47-
struct iov_iter iters[NFSLOCAL_MAX_IOS] ____cacheline_aligned;
4848
/* End mostly DIO-specific members */
4949
};
5050

@@ -339,8 +339,6 @@ nfs_is_local_dio_possible(struct nfs_local_kiocb *iocb, int rw,
339339

340340
if (unlikely(!nf_dio_mem_align || !nf_dio_offset_align))
341341
return false;
342-
if (unlikely(nf_dio_offset_align > PAGE_SIZE))
343-
return false;
344342
if (unlikely(len < nf_dio_offset_align))
345343
return false;
346344

fs/nfs/namespace.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
149149
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
150150
struct nfs_server *server = NFS_SB(path->dentry->d_sb);
151151
struct nfs_client *client = server->nfs_client;
152+
unsigned long s_flags = path->dentry->d_sb->s_flags;
152153
int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
153154
int ret;
154155

@@ -169,11 +170,21 @@ struct vfsmount *nfs_d_automount(struct path *path)
169170
if (!ctx->clone_data.fattr)
170171
goto out_fc;
171172

173+
if (fc->cred != server->cred) {
174+
put_cred(fc->cred);
175+
fc->cred = get_cred(server->cred);
176+
}
177+
172178
if (fc->net_ns != client->cl_net) {
173179
put_net(fc->net_ns);
174180
fc->net_ns = get_net(client->cl_net);
175181
}
176182

183+
/* Inherit the flags covered by NFS_SB_MASK */
184+
fc->sb_flags_mask |= NFS_SB_MASK;
185+
fc->sb_flags &= ~NFS_SB_MASK;
186+
fc->sb_flags |= s_flags & NFS_SB_MASK;
187+
177188
/* for submounts we want the same server; referrals will reassign */
178189
memcpy(&ctx->nfs_server._address, &client->cl_addr, client->cl_addrlen);
179190
ctx->nfs_server.addrlen = client->cl_addrlen;
@@ -184,6 +195,10 @@ struct vfsmount *nfs_d_automount(struct path *path)
184195
ctx->nfs_mod = client->cl_nfs_mod;
185196
get_nfs_version(ctx->nfs_mod);
186197

198+
/* Inherit block sizes if they were specified as mount parameters */
199+
if (server->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE)
200+
ctx->bsize = server->bsize;
201+
187202
ret = client->rpc_ops->submount(fc, server);
188203
if (ret < 0) {
189204
mnt = ERR_PTR(ret);
@@ -283,7 +298,6 @@ int nfs_do_submount(struct fs_context *fc)
283298
return -ENOMEM;
284299

285300
ctx->internal = true;
286-
ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
287301

288302
p = nfs_devname(dentry, buffer, 4096);
289303
if (IS_ERR(p)) {

0 commit comments

Comments
 (0)