Skip to content

Commit 8a1f006

Browse files
committed
Merge tag 'nfs-for-3.14-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: "Highlights: - Fix several races in nfs_revalidate_mapping - NFSv4.1 slot leakage in the pNFS files driver - Stable fix for a slot leak in nfs40_sequence_done - Don't reject NFSv4 servers that support ACLs with only ALLOW aces" * tag 'nfs-for-3.14-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: nfs: initialize the ACL support bits to zero. NFSv4.1: Cleanup NFSv4.1: Clean up nfs41_sequence_done NFSv4: Fix a slot leak in nfs40_sequence_done NFSv4.1 free slot before resending I/O to MDS nfs: add memory barriers around NFS_INO_INVALID_DATA and NFS_INO_INVALIDATING NFS: Fix races in nfs_revalidate_mapping sunrpc: turn warn_gssd() log message into a dprintk() NFS: fix the handling of NFS_INO_INVALID_DATA flag in nfs_revalidate_mapping nfs: handle servers that support only ALLOW ACE type.
2 parents 14864a5 + a1800ac commit 8a1f006

File tree

11 files changed

+86
-42
lines changed

11 files changed

+86
-42
lines changed

fs/nfs/dir.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
274274
return -EBADCOOKIE;
275275
}
276276

277+
static bool
278+
nfs_readdir_inode_mapping_valid(struct nfs_inode *nfsi)
279+
{
280+
if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
281+
return false;
282+
smp_rmb();
283+
return !test_bit(NFS_INO_INVALIDATING, &nfsi->flags);
284+
}
285+
277286
static
278287
int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
279288
{
@@ -287,8 +296,8 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
287296
struct nfs_open_dir_context *ctx = desc->file->private_data;
288297

289298
new_pos = desc->current_index + i;
290-
if (ctx->attr_gencount != nfsi->attr_gencount
291-
|| (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) {
299+
if (ctx->attr_gencount != nfsi->attr_gencount ||
300+
!nfs_readdir_inode_mapping_valid(nfsi)) {
292301
ctx->duped = 0;
293302
ctx->attr_gencount = nfsi->attr_gencount;
294303
} else if (new_pos < desc->ctx->pos) {

fs/nfs/inode.c

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -977,11 +977,11 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
977977
if (ret < 0)
978978
return ret;
979979
}
980-
spin_lock(&inode->i_lock);
981-
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
982-
if (S_ISDIR(inode->i_mode))
980+
if (S_ISDIR(inode->i_mode)) {
981+
spin_lock(&inode->i_lock);
983982
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
984-
spin_unlock(&inode->i_lock);
983+
spin_unlock(&inode->i_lock);
984+
}
985985
nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
986986
nfs_fscache_wait_on_invalidate(inode);
987987

@@ -1008,6 +1008,7 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
10081008
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
10091009
{
10101010
struct nfs_inode *nfsi = NFS_I(inode);
1011+
unsigned long *bitlock = &nfsi->flags;
10111012
int ret = 0;
10121013

10131014
/* swapfiles are not supposed to be shared. */
@@ -1019,12 +1020,46 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
10191020
if (ret < 0)
10201021
goto out;
10211022
}
1022-
if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
1023-
trace_nfs_invalidate_mapping_enter(inode);
1024-
ret = nfs_invalidate_mapping(inode, mapping);
1025-
trace_nfs_invalidate_mapping_exit(inode, ret);
1023+
1024+
/*
1025+
* We must clear NFS_INO_INVALID_DATA first to ensure that
1026+
* invalidations that come in while we're shooting down the mappings
1027+
* are respected. But, that leaves a race window where one revalidator
1028+
* can clear the flag, and then another checks it before the mapping
1029+
* gets invalidated. Fix that by serializing access to this part of
1030+
* the function.
1031+
*
1032+
* At the same time, we need to allow other tasks to see whether we
1033+
* might be in the middle of invalidating the pages, so we only set
1034+
* the bit lock here if it looks like we're going to be doing that.
1035+
*/
1036+
for (;;) {
1037+
ret = wait_on_bit(bitlock, NFS_INO_INVALIDATING,
1038+
nfs_wait_bit_killable, TASK_KILLABLE);
1039+
if (ret)
1040+
goto out;
1041+
spin_lock(&inode->i_lock);
1042+
if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
1043+
spin_unlock(&inode->i_lock);
1044+
continue;
1045+
}
1046+
if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
1047+
break;
1048+
spin_unlock(&inode->i_lock);
1049+
goto out;
10261050
}
10271051

1052+
set_bit(NFS_INO_INVALIDATING, bitlock);
1053+
smp_wmb();
1054+
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
1055+
spin_unlock(&inode->i_lock);
1056+
trace_nfs_invalidate_mapping_enter(inode);
1057+
ret = nfs_invalidate_mapping(inode, mapping);
1058+
trace_nfs_invalidate_mapping_exit(inode, ret);
1059+
1060+
clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
1061+
smp_mb__after_clear_bit();
1062+
wake_up_bit(bitlock, NFS_INO_INVALIDATING);
10281063
out:
10291064
return ret;
10301065
}

fs/nfs/nfs4_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
270270
extern int nfs41_setup_sequence(struct nfs4_session *session,
271271
struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
272272
struct rpc_task *task);
273+
extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
273274
extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
274275
extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
275276
extern int nfs4_proc_get_lease_time(struct nfs_client *clp,

fs/nfs/nfs4client.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
372372
__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
373373
__set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
374374

375-
error = -EINVAL;
376-
if (gssd_running(clp->cl_net))
377-
error = nfs_create_rpc_client(clp, timeparms,
378-
RPC_AUTH_GSS_KRB5I);
375+
error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
379376
if (error == -EINVAL)
380377
error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
381378
if (error < 0)

fs/nfs/nfs4filelayout.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,10 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
335335
dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
336336

337337
if (test_bit(NFS_IOHDR_REDO, &rdata->header->flags) &&
338-
task->tk_status == 0)
338+
task->tk_status == 0) {
339+
nfs41_sequence_done(task, &rdata->res.seq_res);
339340
return;
341+
}
340342

341343
/* Note this may cause RPC to be resent */
342344
rdata->header->mds_ops->rpc_call_done(task, data);
@@ -442,8 +444,10 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
442444
struct nfs_write_data *wdata = data;
443445

444446
if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) &&
445-
task->tk_status == 0)
447+
task->tk_status == 0) {
448+
nfs41_sequence_done(task, &wdata->res.seq_res);
446449
return;
450+
}
447451

448452
/* Note this may cause RPC to be resent */
449453
wdata->header->mds_ops->rpc_call_done(task, data);

fs/nfs/nfs4proc.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ static int nfs40_sequence_done(struct rpc_task *task,
539539
struct nfs4_slot *slot = res->sr_slot;
540540
struct nfs4_slot_table *tbl;
541541

542-
if (!RPC_WAS_SENT(task))
542+
if (slot == NULL)
543543
goto out;
544544

545545
tbl = slot->table;
@@ -559,15 +559,10 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
559559
{
560560
struct nfs4_session *session;
561561
struct nfs4_slot_table *tbl;
562+
struct nfs4_slot *slot = res->sr_slot;
562563
bool send_new_highest_used_slotid = false;
563564

564-
if (!res->sr_slot) {
565-
/* just wake up the next guy waiting since
566-
* we may have not consumed a slot after all */
567-
dprintk("%s: No slot\n", __func__);
568-
return;
569-
}
570-
tbl = res->sr_slot->table;
565+
tbl = slot->table;
571566
session = tbl->session;
572567

573568
spin_lock(&tbl->slot_tbl_lock);
@@ -577,11 +572,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
577572
if (tbl->highest_used_slotid > tbl->target_highest_slotid)
578573
send_new_highest_used_slotid = true;
579574

580-
if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
575+
if (nfs41_wake_and_assign_slot(tbl, slot)) {
581576
send_new_highest_used_slotid = false;
582577
goto out_unlock;
583578
}
584-
nfs4_free_slot(tbl, res->sr_slot);
579+
nfs4_free_slot(tbl, slot);
585580

586581
if (tbl->highest_used_slotid != NFS4_NO_SLOT)
587582
send_new_highest_used_slotid = false;
@@ -592,19 +587,20 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
592587
nfs41_server_notify_highest_slotid_update(session->clp);
593588
}
594589

595-
static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
590+
int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
596591
{
597592
struct nfs4_session *session;
598-
struct nfs4_slot *slot;
593+
struct nfs4_slot *slot = res->sr_slot;
599594
struct nfs_client *clp;
600595
bool interrupted = false;
601596
int ret = 1;
602597

598+
if (slot == NULL)
599+
goto out_noaction;
603600
/* don't increment the sequence number if the task wasn't sent */
604601
if (!RPC_WAS_SENT(task))
605602
goto out;
606603

607-
slot = res->sr_slot;
608604
session = slot->table->session;
609605

610606
if (slot->interrupted) {
@@ -679,6 +675,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
679675
/* The session may be reset by one of the error handlers. */
680676
dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
681677
nfs41_sequence_free_slot(res);
678+
out_noaction:
682679
return ret;
683680
retry_nowait:
684681
if (rpc_restart_call_prepare(task)) {
@@ -692,6 +689,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
692689
rpc_delay(task, NFS4_POLL_RETRY_MAX);
693690
return 0;
694691
}
692+
EXPORT_SYMBOL_GPL(nfs41_sequence_done);
695693

696694
static int nfs4_sequence_done(struct rpc_task *task,
697695
struct nfs4_sequence_res *res)
@@ -2744,7 +2742,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
27442742
NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
27452743
NFS_CAP_CTIME|NFS_CAP_MTIME|
27462744
NFS_CAP_SECURITY_LABEL);
2747-
if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
2745+
if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
2746+
res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
27482747
server->caps |= NFS_CAP_ACLS;
27492748
if (res.has_links != 0)
27502749
server->caps |= NFS_CAP_HARDLINKS;
@@ -4321,9 +4320,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
43214320

43224321
static inline int nfs4_server_supports_acls(struct nfs_server *server)
43234322
{
4324-
return (server->caps & NFS_CAP_ACLS)
4325-
&& (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
4326-
&& (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
4323+
return server->caps & NFS_CAP_ACLS;
43274324
}
43284325

43294326
/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that

fs/nfs/nfs4xdr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3449,7 +3449,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
34493449
{
34503450
__be32 *p;
34513451

3452-
*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
3452+
*res = 0;
34533453
if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
34543454
return -EIO;
34553455
if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {

fs/nfs/nfstrace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
__print_flags(v, "|", \
3737
{ 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \
3838
{ 1 << NFS_INO_STALE, "STALE" }, \
39+
{ 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
3940
{ 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
4041
{ 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
4142
{ 1 << NFS_INO_COMMIT, "COMMIT" }, \

fs/nfs/write.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,9 +909,14 @@ bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx)
909909
*/
910910
static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
911911
{
912+
struct nfs_inode *nfsi = NFS_I(inode);
913+
912914
if (nfs_have_delegated_attributes(inode))
913915
goto out;
914-
if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE))
916+
if (nfsi->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE))
917+
return false;
918+
smp_rmb();
919+
if (test_bit(NFS_INO_INVALIDATING, &nfsi->flags))
915920
return false;
916921
out:
917922
return PageUptodate(page) != 0;

include/linux/nfs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ struct nfs_inode {
211211
#define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */
212212
#define NFS_INO_STALE (1) /* possible stale inode */
213213
#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
214+
#define NFS_INO_INVALIDATING (3) /* inode is being invalidated */
214215
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
215216
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
216217
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */

net/sunrpc/auth_gss/auth_gss.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,7 @@ gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
532532

533533
static void warn_gssd(void)
534534
{
535-
static unsigned long ratelimit;
536-
unsigned long now = jiffies;
537-
538-
if (time_after(now, ratelimit)) {
539-
pr_warn("RPC: AUTH_GSS upcall failed. Please check user daemon is running.\n");
540-
ratelimit = now + 15*HZ;
541-
}
535+
dprintk("AUTH_GSS upcall failed. Please check user daemon is running.\n");
542536
}
543537

544538
static inline int

0 commit comments

Comments
 (0)