Skip to content

Commit e12912d

Browse files
trondmypdamschuma-ntap
authored andcommitted
NFSv4: Add support for delegated atime and mtime attributes
Ensure that we update the mtime and atime correctly when we read or write data to the file and when we truncate. Let the server manage ctime on other attribute updates. Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Lance Shelton <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 4201916 commit e12912d

File tree

6 files changed

+124
-20
lines changed

6 files changed

+124
-20
lines changed

fs/nfs/delegation.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ static int nfs4_do_check_delegation(struct inode *inode, fmode_t type,
115115
if (mark)
116116
nfs_mark_delegation_referenced(delegation);
117117
ret = 1;
118+
if ((flags & NFS_DELEGATION_FLAG_TIME) &&
119+
!test_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags))
120+
ret = 0;
118121
}
119122
rcu_read_unlock();
120123
return ret;
@@ -221,11 +224,12 @@ static int nfs_delegation_claim_opens(struct inode *inode,
221224
* @type: delegation type
222225
* @stateid: delegation stateid
223226
* @pagemod_limit: write delegation "space_limit"
227+
* @deleg_type: raw delegation type
224228
*
225229
*/
226230
void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
227231
fmode_t type, const nfs4_stateid *stateid,
228-
unsigned long pagemod_limit)
232+
unsigned long pagemod_limit, u32 deleg_type)
229233
{
230234
struct nfs_delegation *delegation;
231235
const struct cred *oldcred = NULL;
@@ -239,6 +243,14 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
239243
delegation->pagemod_limit = pagemod_limit;
240244
oldcred = delegation->cred;
241245
delegation->cred = get_cred(cred);
246+
switch (deleg_type) {
247+
case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
248+
case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
249+
set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
250+
break;
251+
default:
252+
clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
253+
}
242254
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
243255
if (test_and_clear_bit(NFS_DELEGATION_REVOKED,
244256
&delegation->flags))
@@ -250,7 +262,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
250262
} else {
251263
rcu_read_unlock();
252264
nfs_inode_set_delegation(inode, cred, type, stateid,
253-
pagemod_limit);
265+
pagemod_limit, deleg_type);
254266
}
255267
}
256268

@@ -418,13 +430,13 @@ nfs_update_inplace_delegation(struct nfs_delegation *delegation,
418430
* @type: delegation type
419431
* @stateid: delegation stateid
420432
* @pagemod_limit: write delegation "space_limit"
433+
* @deleg_type: raw delegation type
421434
*
422435
* Returns zero on success, or a negative errno value.
423436
*/
424437
int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
425-
fmode_t type,
426-
const nfs4_stateid *stateid,
427-
unsigned long pagemod_limit)
438+
fmode_t type, const nfs4_stateid *stateid,
439+
unsigned long pagemod_limit, u32 deleg_type)
428440
{
429441
struct nfs_server *server = NFS_SERVER(inode);
430442
struct nfs_client *clp = server->nfs_client;
@@ -444,6 +456,11 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
444456
delegation->cred = get_cred(cred);
445457
delegation->inode = inode;
446458
delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
459+
switch (deleg_type) {
460+
case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
461+
case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
462+
delegation->flags |= BIT(NFS_DELEGATION_DELEGTIME);
463+
}
447464
delegation->test_gen = 0;
448465
spin_lock_init(&delegation->lock);
449466

@@ -508,6 +525,11 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
508525
atomic_long_inc(&nfs_active_delegations);
509526

510527
trace_nfs4_set_delegation(inode, type);
528+
529+
/* If we hold writebacks and have delegated mtime then update */
530+
if (deleg_type == NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG &&
531+
nfs_have_writebacks(inode))
532+
nfs_update_delegated_mtime(inode);
511533
out:
512534
spin_unlock(&clp->cl_lock);
513535
if (delegation != NULL)

fs/nfs/delegation.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ enum {
3838
NFS_DELEGATION_TEST_EXPIRED,
3939
NFS_DELEGATION_INODE_FREEING,
4040
NFS_DELEGATION_RETURN_DELAYED,
41+
NFS_DELEGATION_DELEGTIME,
4142
};
4243

4344
int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
44-
fmode_t type, const nfs4_stateid *stateid, unsigned long pagemod_limit);
45+
fmode_t type, const nfs4_stateid *stateid,
46+
unsigned long pagemod_limit, u32 deleg_type);
4547
void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
46-
fmode_t type, const nfs4_stateid *stateid, unsigned long pagemod_limit);
48+
fmode_t type, const nfs4_stateid *stateid,
49+
unsigned long pagemod_limit, u32 deleg_type);
4750
int nfs4_inode_return_delegation(struct inode *inode);
4851
void nfs4_inode_return_delegation_on_close(struct inode *inode);
4952
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
@@ -84,6 +87,12 @@ int nfs4_inode_make_writeable(struct inode *inode);
8487

8588
#endif
8689

90+
#define NFS_DELEGATION_FLAG_TIME BIT(1)
91+
92+
void nfs_update_delegated_atime(struct inode *inode);
93+
void nfs_update_delegated_mtime(struct inode *inode);
94+
void nfs_update_delegated_mtime_locked(struct inode *inode);
95+
8796
static inline int nfs_have_read_or_write_delegation(struct inode *inode)
8897
{
8998
return NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0);
@@ -99,4 +108,16 @@ static inline int nfs_have_delegated_attributes(struct inode *inode)
99108
return NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0);
100109
}
101110

111+
static inline int nfs_have_delegated_atime(struct inode *inode)
112+
{
113+
return NFS_PROTO(inode)->have_delegation(inode, FMODE_READ,
114+
NFS_DELEGATION_FLAG_TIME);
115+
}
116+
117+
static inline int nfs_have_delegated_mtime(struct inode *inode)
118+
{
119+
return NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE,
120+
NFS_DELEGATION_FLAG_TIME);
121+
}
122+
102123
#endif

fs/nfs/inode.c

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ EXPORT_SYMBOL_GPL(nfs_zap_acl_cache);
275275

276276
void nfs_invalidate_atime(struct inode *inode)
277277
{
278+
if (nfs_have_delegated_atime(inode))
279+
return;
278280
spin_lock(&inode->i_lock);
279281
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
280282
spin_unlock(&inode->i_lock);
@@ -604,6 +606,33 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
604606
}
605607
EXPORT_SYMBOL_GPL(nfs_fhget);
606608

609+
void nfs_update_delegated_atime(struct inode *inode)
610+
{
611+
spin_lock(&inode->i_lock);
612+
if (nfs_have_delegated_atime(inode)) {
613+
inode_update_timestamps(inode, S_ATIME);
614+
NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ATIME;
615+
}
616+
spin_unlock(&inode->i_lock);
617+
}
618+
619+
void nfs_update_delegated_mtime_locked(struct inode *inode)
620+
{
621+
if (nfs_have_delegated_mtime(inode)) {
622+
inode_update_timestamps(inode, S_CTIME | S_MTIME);
623+
NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_CTIME |
624+
NFS_INO_INVALID_MTIME);
625+
}
626+
}
627+
628+
void nfs_update_delegated_mtime(struct inode *inode)
629+
{
630+
spin_lock(&inode->i_lock);
631+
nfs_update_delegated_mtime_locked(inode);
632+
spin_unlock(&inode->i_lock);
633+
}
634+
EXPORT_SYMBOL_GPL(nfs_update_delegated_mtime);
635+
607636
#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)
608637

609638
int
@@ -631,6 +660,17 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
631660
attr->ia_valid &= ~ATTR_SIZE;
632661
}
633662

663+
if (nfs_have_delegated_mtime(inode)) {
664+
if (attr->ia_valid & ATTR_MTIME) {
665+
nfs_update_delegated_mtime(inode);
666+
attr->ia_valid &= ~ATTR_MTIME;
667+
}
668+
if (attr->ia_valid & ATTR_ATIME) {
669+
nfs_update_delegated_atime(inode);
670+
attr->ia_valid &= ~ATTR_ATIME;
671+
}
672+
}
673+
634674
/* Optimization: if the end result is no change, don't RPC */
635675
if (((attr->ia_valid & NFS_VALID_ATTRS) & ~(ATTR_FILE|ATTR_OPEN)) == 0)
636676
return 0;
@@ -686,6 +726,7 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
686726

687727
spin_unlock(&inode->i_lock);
688728
truncate_pagecache(inode, offset);
729+
nfs_update_delegated_mtime_locked(inode);
689730
spin_lock(&inode->i_lock);
690731
out:
691732
return err;
@@ -709,8 +750,9 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
709750
spin_lock(&inode->i_lock);
710751
NFS_I(inode)->attr_gencount = fattr->gencount;
711752
if ((attr->ia_valid & ATTR_SIZE) != 0) {
712-
nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME |
713-
NFS_INO_INVALID_BLOCKS);
753+
if (!nfs_have_delegated_mtime(inode))
754+
nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
755+
nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
714756
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
715757
nfs_vmtruncate(inode, attr->ia_size);
716758
}
@@ -856,8 +898,12 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
856898

857899
/* Flush out writes to the server in order to update c/mtime/version. */
858900
if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_CHANGE_COOKIE)) &&
859-
S_ISREG(inode->i_mode))
860-
filemap_write_and_wait(inode->i_mapping);
901+
S_ISREG(inode->i_mode)) {
902+
if (nfs_have_delegated_mtime(inode))
903+
filemap_fdatawrite(inode->i_mapping);
904+
else
905+
filemap_write_and_wait(inode->i_mapping);
906+
}
861907

862908
/*
863909
* We may force a getattr if the user cares about atime.

fs/nfs/nfs4proc.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,8 @@ nfs4_update_changeattr_locked(struct inode *inode,
12451245
struct nfs_inode *nfsi = NFS_I(inode);
12461246
u64 change_attr = inode_peek_iversion_raw(inode);
12471247

1248-
cache_validity |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
1248+
if (!nfs_have_delegated_mtime(inode))
1249+
cache_validity |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
12491250
if (S_ISDIR(inode->i_mode))
12501251
cache_validity |= NFS_INO_INVALID_DATA;
12511252

@@ -1961,6 +1962,8 @@ nfs4_process_delegation(struct inode *inode, const struct cred *cred,
19611962
switch (delegation->open_delegation_type) {
19621963
case NFS4_OPEN_DELEGATE_READ:
19631964
case NFS4_OPEN_DELEGATE_WRITE:
1965+
case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
1966+
case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
19641967
break;
19651968
default:
19661969
return;
@@ -1974,16 +1977,16 @@ nfs4_process_delegation(struct inode *inode, const struct cred *cred,
19741977
NFS_SERVER(inode)->nfs_client->cl_hostname);
19751978
break;
19761979
case NFS4_OPEN_CLAIM_PREVIOUS:
1977-
nfs_inode_reclaim_delegation(inode, cred,
1978-
delegation->type,
1979-
&delegation->stateid,
1980-
delegation->pagemod_limit);
1980+
nfs_inode_reclaim_delegation(inode, cred, delegation->type,
1981+
&delegation->stateid,
1982+
delegation->pagemod_limit,
1983+
delegation->open_delegation_type);
19811984
break;
19821985
default:
1983-
nfs_inode_set_delegation(inode, cred,
1984-
delegation->type,
1985-
&delegation->stateid,
1986-
delegation->pagemod_limit);
1986+
nfs_inode_set_delegation(inode, cred, delegation->type,
1987+
&delegation->stateid,
1988+
delegation->pagemod_limit,
1989+
delegation->open_delegation_type);
19871990
}
19881991
if (delegation->do_recall)
19891992
nfs_async_inode_return_delegation(inode, &delegation->stateid);

fs/nfs/read.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "fscache.h"
2929
#include "pnfs.h"
3030
#include "nfstrace.h"
31+
#include "delegation.h"
3132

3233
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
3334

@@ -372,6 +373,7 @@ int nfs_read_folio(struct file *file, struct folio *folio)
372373
goto out_put;
373374

374375
nfs_pageio_complete_read(&pgio);
376+
nfs_update_delegated_atime(inode);
375377
ret = pgio.pg_error < 0 ? pgio.pg_error : 0;
376378
if (!ret) {
377379
ret = folio_wait_locked_killable(folio);
@@ -428,6 +430,7 @@ void nfs_readahead(struct readahead_control *ractl)
428430
}
429431

430432
nfs_pageio_complete_read(&pgio);
433+
nfs_update_delegated_atime(inode);
431434

432435
put_nfs_open_context(ctx);
433436
out:

fs/nfs/write.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ static void nfs_grow_file(struct folio *folio, unsigned int offset,
289289
NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE;
290290
nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
291291
out:
292+
/* Atomically update timestamps if they are delegated to us. */
293+
nfs_update_delegated_mtime_locked(inode);
292294
spin_unlock(&inode->i_lock);
293295
nfs_fscache_invalidate(inode, 0);
294296
}
@@ -1514,6 +1516,13 @@ void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
15141516
struct nfs_fattr *fattr = &hdr->fattr;
15151517
struct inode *inode = hdr->inode;
15161518

1519+
if (nfs_have_delegated_mtime(inode)) {
1520+
spin_lock(&inode->i_lock);
1521+
nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
1522+
spin_unlock(&inode->i_lock);
1523+
return;
1524+
}
1525+
15171526
spin_lock(&inode->i_lock);
15181527
nfs_writeback_check_extend(hdr, fattr);
15191528
nfs_post_op_update_inode_force_wcc_locked(inode, fattr);

0 commit comments

Comments
 (0)