@@ -127,6 +127,7 @@ static void free_session(struct nfsd4_session *);
127
127
128
128
static const struct nfsd4_callback_ops nfsd4_cb_recall_ops ;
129
129
static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops ;
130
+ static const struct nfsd4_callback_ops nfsd4_cb_getattr_ops ;
130
131
131
132
static struct workqueue_struct * laundry_wq ;
132
133
@@ -1189,6 +1190,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
1189
1190
dp -> dl_recalled = false;
1190
1191
nfsd4_init_cb (& dp -> dl_recall , dp -> dl_stid .sc_client ,
1191
1192
& nfsd4_cb_recall_ops , NFSPROC4_CLNT_CB_RECALL );
1193
+ nfsd4_init_cb (& dp -> dl_cb_fattr .ncf_getattr , dp -> dl_stid .sc_client ,
1194
+ & nfsd4_cb_getattr_ops , NFSPROC4_CLNT_CB_GETATTR );
1195
+ dp -> dl_cb_fattr .ncf_file_modified = false;
1196
+ dp -> dl_cb_fattr .ncf_cb_bmap [0 ] = FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE ;
1192
1197
get_nfs4_file (fp );
1193
1198
dp -> dl_stid .sc_file = fp ;
1194
1199
return dp ;
@@ -3044,11 +3049,59 @@ nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
3044
3049
spin_unlock (& nn -> client_lock );
3045
3050
}
3046
3051
3052
+ static int
3053
+ nfsd4_cb_getattr_done (struct nfsd4_callback * cb , struct rpc_task * task )
3054
+ {
3055
+ struct nfs4_cb_fattr * ncf =
3056
+ container_of (cb , struct nfs4_cb_fattr , ncf_getattr );
3057
+
3058
+ ncf -> ncf_cb_status = task -> tk_status ;
3059
+ switch (task -> tk_status ) {
3060
+ case - NFS4ERR_DELAY :
3061
+ rpc_delay (task , 2 * HZ );
3062
+ return 0 ;
3063
+ default :
3064
+ return 1 ;
3065
+ }
3066
+ }
3067
+
3068
+ static void
3069
+ nfsd4_cb_getattr_release (struct nfsd4_callback * cb )
3070
+ {
3071
+ struct nfs4_cb_fattr * ncf =
3072
+ container_of (cb , struct nfs4_cb_fattr , ncf_getattr );
3073
+ struct nfs4_delegation * dp =
3074
+ container_of (ncf , struct nfs4_delegation , dl_cb_fattr );
3075
+
3076
+ nfs4_put_stid (& dp -> dl_stid );
3077
+ clear_bit (CB_GETATTR_BUSY , & ncf -> ncf_cb_flags );
3078
+ wake_up_bit (& ncf -> ncf_cb_flags , CB_GETATTR_BUSY );
3079
+ }
3080
+
3047
3081
static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
3048
3082
.done = nfsd4_cb_recall_any_done ,
3049
3083
.release = nfsd4_cb_recall_any_release ,
3050
3084
};
3051
3085
3086
+ static const struct nfsd4_callback_ops nfsd4_cb_getattr_ops = {
3087
+ .done = nfsd4_cb_getattr_done ,
3088
+ .release = nfsd4_cb_getattr_release ,
3089
+ };
3090
+
3091
+ static void nfs4_cb_getattr (struct nfs4_cb_fattr * ncf )
3092
+ {
3093
+ struct nfs4_delegation * dp =
3094
+ container_of (ncf , struct nfs4_delegation , dl_cb_fattr );
3095
+
3096
+ if (test_and_set_bit (CB_GETATTR_BUSY , & ncf -> ncf_cb_flags ))
3097
+ return ;
3098
+ /* set to proper status when nfsd4_cb_getattr_done runs */
3099
+ ncf -> ncf_cb_status = NFS4ERR_IO ;
3100
+
3101
+ refcount_inc (& dp -> dl_stid .sc_count );
3102
+ nfsd4_run_cb (& ncf -> ncf_getattr );
3103
+ }
3104
+
3052
3105
static struct nfs4_client * create_client (struct xdr_netobj name ,
3053
3106
struct svc_rqst * rqstp , nfs4_verifier * verf )
3054
3107
{
@@ -5854,6 +5907,8 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
5854
5907
struct svc_fh * parent = NULL ;
5855
5908
int cb_up ;
5856
5909
int status = 0 ;
5910
+ struct kstat stat ;
5911
+ struct path path ;
5857
5912
5858
5913
cb_up = nfsd4_cb_channel_good (oo -> oo_owner .so_client );
5859
5914
open -> op_recall = false;
@@ -5891,6 +5946,18 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
5891
5946
if (open -> op_share_access & NFS4_SHARE_ACCESS_WRITE ) {
5892
5947
open -> op_delegate_type = NFS4_OPEN_DELEGATE_WRITE ;
5893
5948
trace_nfsd_deleg_write (& dp -> dl_stid .sc_stateid );
5949
+ path .mnt = currentfh -> fh_export -> ex_path .mnt ;
5950
+ path .dentry = currentfh -> fh_dentry ;
5951
+ if (vfs_getattr (& path , & stat ,
5952
+ (STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE ),
5953
+ AT_STATX_SYNC_AS_STAT )) {
5954
+ nfs4_put_stid (& dp -> dl_stid );
5955
+ destroy_delegation (dp );
5956
+ goto out_no_deleg ;
5957
+ }
5958
+ dp -> dl_cb_fattr .ncf_cur_fsize = stat .size ;
5959
+ dp -> dl_cb_fattr .ncf_initial_cinfo =
5960
+ nfsd4_change_attribute (& stat , d_inode (currentfh -> fh_dentry ));
5894
5961
} else {
5895
5962
open -> op_delegate_type = NFS4_OPEN_DELEGATE_READ ;
5896
5963
trace_nfsd_deleg_read (& dp -> dl_stid .sc_stateid );
@@ -8710,6 +8777,8 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
8710
8777
* nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict
8711
8778
* @rqstp: RPC transaction context
8712
8779
* @inode: file to be checked for a conflict
8780
+ * @modified: return true if file was modified
8781
+ * @size: new size of file if modified is true
8713
8782
*
8714
8783
* This function is called when there is a conflict between a write
8715
8784
* delegation and a change/size GETATTR from another client. The server
@@ -8718,22 +8787,22 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
8718
8787
* delegation before replying to the GETATTR. See RFC 8881 section
8719
8788
* 18.7.4.
8720
8789
*
8721
- * The current implementation does not support CB_GETATTR yet. However
8722
- * this can avoid recalling the delegation could be added in follow up
8723
- * work.
8724
- *
8725
8790
* Returns 0 if there is no conflict; otherwise an nfs_stat
8726
8791
* code is returned.
8727
8792
*/
8728
8793
__be32
8729
- nfsd4_deleg_getattr_conflict (struct svc_rqst * rqstp , struct inode * inode )
8794
+ nfsd4_deleg_getattr_conflict (struct svc_rqst * rqstp , struct inode * inode ,
8795
+ bool * modified , u64 * size )
8730
8796
{
8731
8797
__be32 status ;
8732
8798
struct nfsd_net * nn = net_generic (SVC_NET (rqstp ), nfsd_net_id );
8733
8799
struct file_lock_context * ctx ;
8734
8800
struct file_lock * fl ;
8735
8801
struct nfs4_delegation * dp ;
8802
+ struct iattr attrs ;
8803
+ struct nfs4_cb_fattr * ncf ;
8736
8804
8805
+ * modified = false;
8737
8806
ctx = locks_inode_context (inode );
8738
8807
if (!ctx )
8739
8808
return 0 ;
@@ -8758,12 +8827,38 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
8758
8827
return 0 ;
8759
8828
}
8760
8829
break_lease :
8761
- spin_unlock (& ctx -> flc_lock );
8762
8830
nfsd_stats_wdeleg_getattr_inc (nn );
8763
- status = nfserrno (nfsd_open_break_lease (inode , NFSD_MAY_READ ));
8764
- if (status != nfserr_jukebox ||
8765
- !nfsd_wait_for_delegreturn (rqstp , inode ))
8766
- return status ;
8831
+ dp = fl -> fl_owner ;
8832
+ ncf = & dp -> dl_cb_fattr ;
8833
+ nfs4_cb_getattr (& dp -> dl_cb_fattr );
8834
+ spin_unlock (& ctx -> flc_lock );
8835
+ wait_on_bit_timeout (& ncf -> ncf_cb_flags , CB_GETATTR_BUSY ,
8836
+ TASK_INTERRUPTIBLE , NFSD_CB_GETATTR_TIMEOUT );
8837
+ if (ncf -> ncf_cb_status ) {
8838
+ /* Recall delegation only if client didn't respond */
8839
+ status = nfserrno (nfsd_open_break_lease (inode , NFSD_MAY_READ ));
8840
+ if (status != nfserr_jukebox ||
8841
+ !nfsd_wait_for_delegreturn (rqstp , inode ))
8842
+ return status ;
8843
+ }
8844
+ if (!ncf -> ncf_file_modified &&
8845
+ (ncf -> ncf_initial_cinfo != ncf -> ncf_cb_change ||
8846
+ ncf -> ncf_cur_fsize != ncf -> ncf_cb_fsize ))
8847
+ ncf -> ncf_file_modified = true;
8848
+ if (ncf -> ncf_file_modified ) {
8849
+ /*
8850
+ * Per section 10.4.3 of RFC 8881, the server would
8851
+ * not update the file's metadata with the client's
8852
+ * modified size
8853
+ */
8854
+ attrs .ia_mtime = attrs .ia_ctime = current_time (inode );
8855
+ attrs .ia_valid = ATTR_MTIME | ATTR_CTIME ;
8856
+ setattr_copy (& nop_mnt_idmap , inode , & attrs );
8857
+ mark_inode_dirty (inode );
8858
+ ncf -> ncf_cur_fsize = ncf -> ncf_cb_fsize ;
8859
+ * size = ncf -> ncf_cur_fsize ;
8860
+ * modified = true;
8861
+ }
8767
8862
return 0 ;
8768
8863
}
8769
8864
break ;
0 commit comments