diff options
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 62 |
1 files changed, 39 insertions, 23 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7d031cd7d920..3afa82e45438 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -230,32 +230,41 @@ static void free_lseg(struct pnfs_layout_segment *lseg) | |||
230 | put_layout_hdr(NFS_I(ino)->layout); | 230 | put_layout_hdr(NFS_I(ino)->layout); |
231 | } | 231 | } |
232 | 232 | ||
233 | /* The use of tmp_list is necessary because pnfs_curr_ld->free_lseg | 233 | static void |
234 | * could sleep, so must be called outside of the lock. | 234 | put_lseg_common(struct pnfs_layout_segment *lseg) |
235 | * Returns 1 if object was removed, otherwise return 0. | 235 | { |
236 | */ | 236 | struct inode *inode = lseg->pls_layout->plh_inode; |
237 | static int | 237 | |
238 | put_lseg_locked(struct pnfs_layout_segment *lseg, | 238 | BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); |
239 | struct list_head *tmp_list) | 239 | list_del_init(&lseg->pls_list); |
240 | if (list_empty(&lseg->pls_layout->plh_segs)) { | ||
241 | set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); | ||
242 | /* Matched by initial refcount set in alloc_init_layout_hdr */ | ||
243 | put_layout_hdr_locked(lseg->pls_layout); | ||
244 | } | ||
245 | rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); | ||
246 | } | ||
247 | |||
248 | static void | ||
249 | put_lseg(struct pnfs_layout_segment *lseg) | ||
240 | { | 250 | { |
251 | struct inode *inode; | ||
252 | |||
253 | if (!lseg) | ||
254 | return; | ||
255 | |||
241 | dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg, | 256 | dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg, |
242 | atomic_read(&lseg->pls_refcount), | 257 | atomic_read(&lseg->pls_refcount), |
243 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 258 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); |
244 | if (atomic_dec_and_test(&lseg->pls_refcount)) { | 259 | inode = lseg->pls_layout->plh_inode; |
245 | struct inode *ino = lseg->pls_layout->plh_inode; | 260 | if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { |
261 | LIST_HEAD(free_me); | ||
246 | 262 | ||
247 | BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 263 | put_lseg_common(lseg); |
248 | list_del(&lseg->pls_list); | 264 | list_add(&lseg->pls_list, &free_me); |
249 | if (list_empty(&lseg->pls_layout->plh_segs)) { | 265 | spin_unlock(&inode->i_lock); |
250 | set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); | 266 | pnfs_free_lseg_list(&free_me); |
251 | /* Matched by initial refcount set in alloc_init_layout_hdr */ | ||
252 | put_layout_hdr_locked(lseg->pls_layout); | ||
253 | } | ||
254 | rpc_wake_up(&NFS_SERVER(ino)->roc_rpcwaitq); | ||
255 | list_add(&lseg->pls_list, tmp_list); | ||
256 | return 1; | ||
257 | } | 267 | } |
258 | return 0; | ||
259 | } | 268 | } |
260 | 269 | ||
261 | static bool | 270 | static bool |
@@ -276,7 +285,13 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | |||
276 | * list. It will now be removed when all | 285 | * list. It will now be removed when all |
277 | * outstanding io is finished. | 286 | * outstanding io is finished. |
278 | */ | 287 | */ |
279 | rv = put_lseg_locked(lseg, tmp_list); | 288 | dprintk("%s: lseg %p ref %d\n", __func__, lseg, |
289 | atomic_read(&lseg->pls_refcount)); | ||
290 | if (atomic_dec_and_test(&lseg->pls_refcount)) { | ||
291 | put_lseg_common(lseg); | ||
292 | list_add(&lseg->pls_list, tmp_list); | ||
293 | rv = 1; | ||
294 | } | ||
280 | } | 295 | } |
281 | return rv; | 296 | return rv; |
282 | } | 297 | } |
@@ -689,7 +704,7 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) | |||
689 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { | 704 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { |
690 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && | 705 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && |
691 | is_matching_lseg(lseg, iomode)) { | 706 | is_matching_lseg(lseg, iomode)) { |
692 | ret = lseg; | 707 | ret = get_lseg(lseg); |
693 | break; | 708 | break; |
694 | } | 709 | } |
695 | if (cmp_layout(iomode, lseg->pls_range.iomode) > 0) | 710 | if (cmp_layout(iomode, lseg->pls_range.iomode) > 0) |
@@ -769,6 +784,7 @@ pnfs_update_layout(struct inode *ino, | |||
769 | out: | 784 | out: |
770 | dprintk("%s end, state 0x%lx lseg %p\n", __func__, | 785 | dprintk("%s end, state 0x%lx lseg %p\n", __func__, |
771 | nfsi->layout ? nfsi->layout->plh_flags : -1, lseg); | 786 | nfsi->layout ? nfsi->layout->plh_flags : -1, lseg); |
787 | put_lseg(lseg); /* STUB - callers currently ignore return value */ | ||
772 | return lseg; | 788 | return lseg; |
773 | out_unlock: | 789 | out_unlock: |
774 | spin_unlock(&ino->i_lock); | 790 | spin_unlock(&ino->i_lock); |
@@ -821,7 +837,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
821 | } | 837 | } |
822 | init_lseg(lo, lseg); | 838 | init_lseg(lo, lseg); |
823 | lseg->pls_range = res->range; | 839 | lseg->pls_range = res->range; |
824 | *lgp->lsegpp = lseg; | 840 | *lgp->lsegpp = get_lseg(lseg); |
825 | pnfs_insert_layout(lo, lseg); | 841 | pnfs_insert_layout(lo, lseg); |
826 | 842 | ||
827 | if (res->return_on_close) { | 843 | if (res->return_on_close) { |