diff options
Diffstat (limited to 'fs/nfs/callback_proc.c')
-rw-r--r-- | fs/nfs/callback_proc.c | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 807eb6ef4f91..f0939d097406 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -83,8 +83,11 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
83 | 83 | ||
84 | res = htonl(NFS4ERR_BADHANDLE); | 84 | res = htonl(NFS4ERR_BADHANDLE); |
85 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); | 85 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); |
86 | if (inode == NULL) | 86 | if (inode == NULL) { |
87 | trace_nfs4_cb_recall(cps->clp, &args->fh, NULL, | ||
88 | &args->stateid, -ntohl(res)); | ||
87 | goto out; | 89 | goto out; |
90 | } | ||
88 | /* Set up a helper thread to actually return the delegation */ | 91 | /* Set up a helper thread to actually return the delegation */ |
89 | switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { | 92 | switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { |
90 | case 0: | 93 | case 0: |
@@ -96,7 +99,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
96 | default: | 99 | default: |
97 | res = htonl(NFS4ERR_RESOURCE); | 100 | res = htonl(NFS4ERR_RESOURCE); |
98 | } | 101 | } |
99 | trace_nfs4_recall_delegation(inode, -ntohl(res)); | 102 | trace_nfs4_cb_recall(cps->clp, &args->fh, inode, |
103 | &args->stateid, -ntohl(res)); | ||
100 | iput(inode); | 104 | iput(inode); |
101 | out: | 105 | out: |
102 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 106 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
@@ -160,6 +164,22 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, | |||
160 | return lo; | 164 | return lo; |
161 | } | 165 | } |
162 | 166 | ||
167 | /* | ||
168 | * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing) | ||
169 | */ | ||
170 | static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo, | ||
171 | const nfs4_stateid *new) | ||
172 | { | ||
173 | u32 oldseq, newseq; | ||
174 | |||
175 | oldseq = be32_to_cpu(lo->plh_stateid.seqid); | ||
176 | newseq = be32_to_cpu(new->seqid); | ||
177 | |||
178 | if (newseq > oldseq + 1) | ||
179 | return false; | ||
180 | return true; | ||
181 | } | ||
182 | |||
163 | static u32 initiate_file_draining(struct nfs_client *clp, | 183 | static u32 initiate_file_draining(struct nfs_client *clp, |
164 | struct cb_layoutrecallargs *args) | 184 | struct cb_layoutrecallargs *args) |
165 | { | 185 | { |
@@ -169,34 +189,52 @@ static u32 initiate_file_draining(struct nfs_client *clp, | |||
169 | LIST_HEAD(free_me_list); | 189 | LIST_HEAD(free_me_list); |
170 | 190 | ||
171 | lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid); | 191 | lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid); |
172 | if (!lo) | 192 | if (!lo) { |
193 | trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL, | ||
194 | &args->cbl_stateid, -rv); | ||
173 | goto out; | 195 | goto out; |
196 | } | ||
174 | 197 | ||
175 | ino = lo->plh_inode; | 198 | ino = lo->plh_inode; |
176 | 199 | ||
177 | spin_lock(&ino->i_lock); | 200 | spin_lock(&ino->i_lock); |
201 | if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) { | ||
202 | rv = NFS4ERR_DELAY; | ||
203 | goto unlock; | ||
204 | } | ||
178 | pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); | 205 | pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); |
179 | spin_unlock(&ino->i_lock); | 206 | spin_unlock(&ino->i_lock); |
180 | 207 | ||
181 | pnfs_layoutcommit_inode(ino, false); | 208 | pnfs_layoutcommit_inode(ino, false); |
182 | 209 | ||
183 | spin_lock(&ino->i_lock); | 210 | spin_lock(&ino->i_lock); |
184 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 211 | /* |
185 | pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, | 212 | * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return) |
186 | &args->cbl_range)) { | 213 | */ |
214 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { | ||
187 | rv = NFS4ERR_DELAY; | 215 | rv = NFS4ERR_DELAY; |
188 | goto unlock; | 216 | goto unlock; |
189 | } | 217 | } |
190 | 218 | ||
219 | if (pnfs_mark_matching_lsegs_return(lo, &free_me_list, | ||
220 | &args->cbl_range)) { | ||
221 | rv = NFS4_OK; | ||
222 | goto unlock; | ||
223 | } | ||
224 | |||
191 | if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { | 225 | if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { |
192 | NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, | 226 | NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, |
193 | &args->cbl_range); | 227 | &args->cbl_range); |
194 | } | 228 | } |
229 | pnfs_mark_layout_returned_if_empty(lo); | ||
195 | unlock: | 230 | unlock: |
196 | spin_unlock(&ino->i_lock); | 231 | spin_unlock(&ino->i_lock); |
197 | pnfs_free_lseg_list(&free_me_list); | 232 | pnfs_free_lseg_list(&free_me_list); |
233 | /* Free all lsegs that are attached to commit buckets */ | ||
234 | nfs_commit_inode(ino, 0); | ||
198 | pnfs_put_layout_hdr(lo); | 235 | pnfs_put_layout_hdr(lo); |
199 | trace_nfs4_cb_layoutrecall_inode(clp, &args->cbl_fh, ino, -rv); | 236 | trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino, |
237 | &args->cbl_stateid, -rv); | ||
200 | iput(ino); | 238 | iput(ino); |
201 | out: | 239 | out: |
202 | return rv; | 240 | return rv; |