@@ -5951,13 +5951,14 @@ static struct nfs4_delegation *
59515951nfs4_set_delegation (struct nfsd4_open * open , struct nfs4_ol_stateid * stp ,
59525952 struct svc_fh * parent )
59535953{
5954- int status = 0 ;
5954+ bool deleg_ts = open -> op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS ;
59555955 struct nfs4_client * clp = stp -> st_stid .sc_client ;
59565956 struct nfs4_file * fp = stp -> st_stid .sc_file ;
59575957 struct nfs4_clnt_odstate * odstate = stp -> st_clnt_odstate ;
59585958 struct nfs4_delegation * dp ;
59595959 struct nfsd_file * nf = NULL ;
59605960 struct file_lease * fl ;
5961+ int status = 0 ;
59615962 u32 dl_type ;
59625963
59635964 /*
@@ -5982,7 +5983,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
59825983 */
59835984 if ((open -> op_share_access & NFS4_SHARE_ACCESS_BOTH ) == NFS4_SHARE_ACCESS_BOTH ) {
59845985 nf = find_rw_file (fp );
5985- dl_type = OPEN_DELEGATE_WRITE ;
5986+ dl_type = deleg_ts ? OPEN_DELEGATE_WRITE_ATTRS_DELEG : OPEN_DELEGATE_WRITE ;
59865987 }
59875988
59885989 /*
@@ -5991,7 +5992,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
59915992 */
59925993 if (!nf && (open -> op_share_access & NFS4_SHARE_ACCESS_READ )) {
59935994 nf = find_readable_file (fp );
5994- dl_type = OPEN_DELEGATE_READ ;
5995+ dl_type = deleg_ts ? OPEN_DELEGATE_READ_ATTRS_DELEG : OPEN_DELEGATE_READ ;
59955996 }
59965997
59975998 if (!nf )
@@ -6149,13 +6150,14 @@ static void
61496150nfs4_open_delegation (struct nfsd4_open * open , struct nfs4_ol_stateid * stp ,
61506151 struct svc_fh * currentfh )
61516152{
6152- struct nfs4_delegation * dp ;
6153+ bool deleg_ts = open -> op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS ;
61536154 struct nfs4_openowner * oo = openowner (stp -> st_stateowner );
61546155 struct nfs4_client * clp = stp -> st_stid .sc_client ;
61556156 struct svc_fh * parent = NULL ;
6156- int cb_up ;
6157- int status = 0 ;
6157+ struct nfs4_delegation * dp ;
61586158 struct kstat stat ;
6159+ int status = 0 ;
6160+ int cb_up ;
61596161
61606162 cb_up = nfsd4_cb_channel_good (oo -> oo_owner .so_client );
61616163 open -> op_recall = false;
@@ -6196,12 +6198,14 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
61966198 destroy_delegation (dp );
61976199 goto out_no_deleg ;
61986200 }
6199- open -> op_delegate_type = OPEN_DELEGATE_WRITE ;
6201+ open -> op_delegate_type = deleg_ts ? OPEN_DELEGATE_WRITE_ATTRS_DELEG :
6202+ OPEN_DELEGATE_WRITE ;
62006203 dp -> dl_cb_fattr .ncf_cur_fsize = stat .size ;
62016204 dp -> dl_cb_fattr .ncf_initial_cinfo = nfsd4_change_attribute (& stat );
62026205 trace_nfsd_deleg_write (& dp -> dl_stid .sc_stateid );
62036206 } else {
6204- open -> op_delegate_type = OPEN_DELEGATE_READ ;
6207+ open -> op_delegate_type = deleg_ts ? OPEN_DELEGATE_READ_ATTRS_DELEG :
6208+ OPEN_DELEGATE_READ ;
62056209 trace_nfsd_deleg_read (& dp -> dl_stid .sc_stateid );
62066210 }
62076211 nfs4_put_stid (& dp -> dl_stid );
@@ -9017,6 +9021,78 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
90179021 get_stateid (cstate , & u -> write .wr_stateid );
90189022}
90199023
9024+ /**
9025+ * set_cb_time - vet and set the timespec for a cb_getattr update
9026+ * @cb: timestamp from the CB_GETATTR response
9027+ * @orig: original timestamp in the inode
9028+ * @now: current time
9029+ *
9030+ * Given a timestamp in a CB_GETATTR response, check it against the
9031+ * current timestamp in the inode and the current time. Returns true
9032+ * if the inode's timestamp needs to be updated, and false otherwise.
9033+ * @cb may also be changed if the timestamp needs to be clamped.
9034+ */
9035+ static bool set_cb_time (struct timespec64 * cb , const struct timespec64 * orig ,
9036+ const struct timespec64 * now )
9037+ {
9038+
9039+ /*
9040+ * "When the time presented is before the original time, then the
9041+ * update is ignored." Also no need to update if there is no change.
9042+ */
9043+ if (timespec64_compare (cb , orig ) <= 0 )
9044+ return false;
9045+
9046+ /*
9047+ * "When the time presented is in the future, the server can either
9048+ * clamp the new time to the current time, or it may
9049+ * return NFS4ERR_DELAY to the client, allowing it to retry."
9050+ */
9051+ if (timespec64_compare (cb , now ) > 0 ) {
9052+ /* clamp it */
9053+ * cb = * now ;
9054+ }
9055+
9056+ return true;
9057+ }
9058+
9059+ static int cb_getattr_update_times (struct dentry * dentry , struct nfs4_delegation * dp )
9060+ {
9061+ struct inode * inode = d_inode (dentry );
9062+ struct timespec64 now = current_time (inode );
9063+ struct nfs4_cb_fattr * ncf = & dp -> dl_cb_fattr ;
9064+ struct iattr attrs = { };
9065+ int ret ;
9066+
9067+ if (deleg_attrs_deleg (dp -> dl_type )) {
9068+ struct timespec64 atime = inode_get_atime (inode );
9069+ struct timespec64 mtime = inode_get_mtime (inode );
9070+
9071+ attrs .ia_atime = ncf -> ncf_cb_atime ;
9072+ attrs .ia_mtime = ncf -> ncf_cb_mtime ;
9073+
9074+ if (set_cb_time (& attrs .ia_atime , & atime , & now ))
9075+ attrs .ia_valid |= ATTR_ATIME | ATTR_ATIME_SET ;
9076+
9077+ if (set_cb_time (& attrs .ia_mtime , & mtime , & now )) {
9078+ attrs .ia_valid |= ATTR_CTIME | ATTR_MTIME | ATTR_MTIME_SET ;
9079+ attrs .ia_ctime = attrs .ia_mtime ;
9080+ }
9081+ } else {
9082+ attrs .ia_valid |= ATTR_MTIME | ATTR_CTIME ;
9083+ attrs .ia_mtime = attrs .ia_ctime = now ;
9084+ }
9085+
9086+ if (!attrs .ia_valid )
9087+ return 0 ;
9088+
9089+ attrs .ia_valid |= ATTR_DELEG ;
9090+ inode_lock (inode );
9091+ ret = notify_change (& nop_mnt_idmap , dentry , & attrs , NULL );
9092+ inode_unlock (inode );
9093+ return ret ;
9094+ }
9095+
90209096/**
90219097 * nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict
90229098 * @rqstp: RPC transaction context
@@ -9043,7 +9119,6 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
90439119 struct file_lock_context * ctx ;
90449120 struct nfs4_delegation * dp = NULL ;
90459121 struct file_lease * fl ;
9046- struct iattr attrs ;
90479122 struct nfs4_cb_fattr * ncf ;
90489123 struct inode * inode = d_inode (dentry );
90499124
@@ -9105,11 +9180,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
91059180 * not update the file's metadata with the client's
91069181 * modified size
91079182 */
9108- attrs .ia_mtime = attrs .ia_ctime = current_time (inode );
9109- attrs .ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_DELEG ;
9110- inode_lock (inode );
9111- err = notify_change (& nop_mnt_idmap , dentry , & attrs , NULL );
9112- inode_unlock (inode );
9183+ err = cb_getattr_update_times (dentry , dp );
91139184 if (err ) {
91149185 status = nfserrno (err );
91159186 goto out_status ;
0 commit comments