aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/callback_proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-02-12 09:48:42 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-02-14 13:22:50 -0500
commitfd9a8d7160937f94aad36ac80d7255b4988740ac (patch)
treee437737b8f918134b2ab26bfb74883b0fc47092d /fs/nfs/callback_proc.c
parentc8da19b9866ea84e9ad1c369393ea95d54ee7845 (diff)
NFSv4.1: Fix bulk recall and destroy of layouts
The current code in pnfs_destroy_all_layouts() assumes that removing the layout from the server->layouts list is sufficient to make it invisible to other processes. This ignores the fact that most users access the layout through the nfs_inode->layout... There is further breakage due to lack of reference counting of the layouts, meaning that the whole thing Oopses at the drop of a hat. The code in initiate_bulk_draining() is almost correct, and can be used as a model for pnfs_destroy_all_layouts(), so move that code to pnfs.c, and refactor the code to allow us to choose between a single filesystem bulk recall, and a recall of all layouts. Also note that initiate_bulk_draining() currently calls iput() while holding locks. Fix that too. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/nfs/callback_proc.c')
-rw-r--r--fs/nfs/callback_proc.c61
1 files changed, 8 insertions, 53 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 264d1aa935f2..2960512792c2 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -183,60 +183,15 @@ static u32 initiate_file_draining(struct nfs_client *clp,
183static u32 initiate_bulk_draining(struct nfs_client *clp, 183static u32 initiate_bulk_draining(struct nfs_client *clp,
184 struct cb_layoutrecallargs *args) 184 struct cb_layoutrecallargs *args)
185{ 185{
186 struct nfs_server *server; 186 int stat;
187 struct pnfs_layout_hdr *lo;
188 struct inode *ino;
189 u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
190 struct pnfs_layout_hdr *tmp;
191 LIST_HEAD(recall_list);
192 LIST_HEAD(free_me_list);
193 struct pnfs_layout_range range = {
194 .iomode = IOMODE_ANY,
195 .offset = 0,
196 .length = NFS4_MAX_UINT64,
197 };
198
199 spin_lock(&clp->cl_lock);
200 rcu_read_lock();
201 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
202 if ((args->cbl_recall_type == RETURN_FSID) &&
203 memcmp(&server->fsid, &args->cbl_fsid,
204 sizeof(struct nfs_fsid)))
205 continue;
206 187
207 list_for_each_entry(lo, &server->layouts, plh_layouts) { 188 if (args->cbl_recall_type == RETURN_FSID)
208 ino = igrab(lo->plh_inode); 189 stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true);
209 if (!ino) 190 else
210 continue; 191 stat = pnfs_destroy_layouts_byclid(clp, true);
211 spin_lock(&ino->i_lock); 192 if (stat != 0)
212 /* Is this layout in the process of being freed? */ 193 return NFS4ERR_DELAY;
213 if (NFS_I(ino)->layout != lo) { 194 return NFS4ERR_NOMATCHING_LAYOUT;
214 spin_unlock(&ino->i_lock);
215 iput(ino);
216 continue;
217 }
218 pnfs_get_layout_hdr(lo);
219 spin_unlock(&ino->i_lock);
220 list_add(&lo->plh_bulk_recall, &recall_list);
221 }
222 }
223 rcu_read_unlock();
224 spin_unlock(&clp->cl_lock);
225
226 list_for_each_entry_safe(lo, tmp,
227 &recall_list, plh_bulk_recall) {
228 ino = lo->plh_inode;
229 spin_lock(&ino->i_lock);
230 set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
231 if (pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, &range))
232 rv = NFS4ERR_DELAY;
233 list_del_init(&lo->plh_bulk_recall);
234 spin_unlock(&ino->i_lock);
235 pnfs_free_lseg_list(&free_me_list);
236 pnfs_put_layout_hdr(lo);
237 iput(ino);
238 }
239 return rv;
240} 195}
241 196
242static u32 do_callback_layoutrecall(struct nfs_client *clp, 197static u32 do_callback_layoutrecall(struct nfs_client *clp,