Skip to content

Commit 3952f1c

Browse files
jtlaytonchucklever
authored andcommitted
nfsd: fix SETATTR updates for delegated timestamps
SETATTRs containing delegated timestamp updates are currently not being vetted properly. Since we no longer need to compare the timestamps vs. the current timestamps, move the vetting of delegated timestamps wholly into nfsd. Rename the set_cb_time() helper to nfsd4_vet_deleg_time(), and make it non-static. Add a new vet_deleg_attrs() helper that is called from nfsd4_setattr that uses nfsd4_vet_deleg_time() to properly validate the all the timestamps. If the validation indicates that the update should be skipped, unset the appropriate flags in ia_valid. Fixes: 7e13f4f ("nfsd: handle delegated timestamps in SETATTR") Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 7663e96 commit 3952f1c

3 files changed

Lines changed: 44 additions & 14 deletions

File tree

fs/nfsd/nfs4proc.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,33 @@ nfsd4_secinfo_no_name_release(union nfsd4_op_u *u)
11331133
exp_put(u->secinfo_no_name.sin_exp);
11341134
}
11351135

1136+
/*
1137+
* Validate that the requested timestamps are within the acceptable range. If
1138+
* timestamp appears to be in the future, then it will be clamped to
1139+
* current_time().
1140+
*/
1141+
static void
1142+
vet_deleg_attrs(struct nfsd4_setattr *setattr, struct nfs4_delegation *dp)
1143+
{
1144+
struct timespec64 now = current_time(dp->dl_stid.sc_file->fi_inode);
1145+
struct iattr *iattr = &setattr->sa_iattr;
1146+
1147+
if ((setattr->sa_bmval[2] & FATTR4_WORD2_TIME_DELEG_ACCESS) &&
1148+
!nfsd4_vet_deleg_time(&iattr->ia_atime, &dp->dl_atime, &now))
1149+
iattr->ia_valid &= ~(ATTR_ATIME | ATTR_ATIME_SET);
1150+
1151+
if (setattr->sa_bmval[2] & FATTR4_WORD2_TIME_DELEG_MODIFY) {
1152+
if (nfsd4_vet_deleg_time(&iattr->ia_mtime, &dp->dl_mtime, &now)) {
1153+
iattr->ia_ctime = iattr->ia_mtime;
1154+
if (!nfsd4_vet_deleg_time(&iattr->ia_ctime, &dp->dl_ctime, &now))
1155+
iattr->ia_valid &= ~(ATTR_CTIME | ATTR_CTIME_SET);
1156+
} else {
1157+
iattr->ia_valid &= ~(ATTR_CTIME | ATTR_CTIME_SET |
1158+
ATTR_MTIME | ATTR_MTIME_SET);
1159+
}
1160+
}
1161+
}
1162+
11361163
static __be32
11371164
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
11381165
union nfsd4_op_u *u)
@@ -1170,8 +1197,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
11701197
struct nfs4_delegation *dp = delegstateid(st);
11711198

11721199
/* Only for *_ATTRS_DELEG flavors */
1173-
if (deleg_attrs_deleg(dp->dl_type))
1200+
if (deleg_attrs_deleg(dp->dl_type)) {
1201+
vet_deleg_attrs(setattr, dp);
11741202
status = nfs_ok;
1203+
}
11751204
}
11761205
}
11771206
if (st)

fs/nfsd/nfs4state.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9135,36 +9135,34 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
91359135
}
91369136

91379137
/**
9138-
* set_cb_time - vet and set the timespec for a cb_getattr update
9139-
* @cb: timestamp from the CB_GETATTR response
9138+
* nfsd4_vet_deleg_time - vet and set the timespec for a delegated timestamp update
9139+
* @req: timestamp from the client
91409140
* @orig: original timestamp in the inode
91419141
* @now: current time
91429142
*
9143-
* Given a timestamp in a CB_GETATTR response, check it against the
9143+
* Given a timestamp from the client response, check it against the
91449144
* current timestamp in the inode and the current time. Returns true
91459145
* if the inode's timestamp needs to be updated, and false otherwise.
9146-
* @cb may also be changed if the timestamp needs to be clamped.
9146+
* @req may also be changed if the timestamp needs to be clamped.
91479147
*/
9148-
static bool set_cb_time(struct timespec64 *cb, const struct timespec64 *orig,
9149-
const struct timespec64 *now)
9148+
bool nfsd4_vet_deleg_time(struct timespec64 *req, const struct timespec64 *orig,
9149+
const struct timespec64 *now)
91509150
{
91519151

91529152
/*
91539153
* "When the time presented is before the original time, then the
91549154
* update is ignored." Also no need to update if there is no change.
91559155
*/
9156-
if (timespec64_compare(cb, orig) <= 0)
9156+
if (timespec64_compare(req, orig) <= 0)
91579157
return false;
91589158

91599159
/*
91609160
* "When the time presented is in the future, the server can either
91619161
* clamp the new time to the current time, or it may
91629162
* return NFS4ERR_DELAY to the client, allowing it to retry."
91639163
*/
9164-
if (timespec64_compare(cb, now) > 0) {
9165-
/* clamp it */
9166-
*cb = *now;
9167-
}
9164+
if (timespec64_compare(req, now) > 0)
9165+
*req = *now;
91689166

91699167
return true;
91709168
}
@@ -9184,10 +9182,10 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation
91849182
attrs.ia_atime = ncf->ncf_cb_atime;
91859183
attrs.ia_mtime = ncf->ncf_cb_mtime;
91869184

9187-
if (set_cb_time(&attrs.ia_atime, &atime, &now))
9185+
if (nfsd4_vet_deleg_time(&attrs.ia_atime, &atime, &now))
91889186
attrs.ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
91899187

9190-
if (set_cb_time(&attrs.ia_mtime, &mtime, &now)) {
9188+
if (nfsd4_vet_deleg_time(&attrs.ia_mtime, &mtime, &now)) {
91919189
attrs.ia_valid |= ATTR_CTIME | ATTR_CTIME_SET |
91929190
ATTR_MTIME | ATTR_MTIME_SET;
91939191
attrs.ia_ctime = attrs.ia_mtime;

fs/nfsd/state.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ static inline bool deleg_attrs_deleg(u32 dl_type)
247247
dl_type == OPEN_DELEGATE_WRITE_ATTRS_DELEG;
248248
}
249249

250+
bool nfsd4_vet_deleg_time(struct timespec64 *cb, const struct timespec64 *orig,
251+
const struct timespec64 *now);
252+
250253
#define cb_to_delegation(cb) \
251254
container_of(cb, struct nfs4_delegation, dl_recall)
252255

0 commit comments

Comments
 (0)