aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/pnfs.c48
-rw-r--r--fs/nfs/pnfs.h4
2 files changed, 28 insertions, 24 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index cd9906415a14..32b66468e5db 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -177,34 +177,38 @@ EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);
177 * pNFS client layout cache 177 * pNFS client layout cache
178 */ 178 */
179 179
180/* Need to hold i_lock if caller does not already hold reference */
180static void 181static void
181get_layout_hdr_locked(struct pnfs_layout_hdr *lo) 182get_layout_hdr(struct pnfs_layout_hdr *lo)
182{ 183{
183 assert_spin_locked(&lo->plh_inode->i_lock); 184 atomic_inc(&lo->plh_refcount);
184 lo->plh_refcount++;
185} 185}
186 186
187static void 187static void
188put_layout_hdr_locked(struct pnfs_layout_hdr *lo) 188destroy_layout_hdr(struct pnfs_layout_hdr *lo)
189{ 189{
190 assert_spin_locked(&lo->plh_inode->i_lock); 190 dprintk("%s: freeing layout cache %p\n", __func__, lo);
191 BUG_ON(lo->plh_refcount == 0); 191 BUG_ON(!list_empty(&lo->plh_layouts));
192 NFS_I(lo->plh_inode)->layout = NULL;
193 kfree(lo);
194}
192 195
193 lo->plh_refcount--; 196static void
194 if (!lo->plh_refcount) { 197put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
195 dprintk("%s: freeing layout cache %p\n", __func__, lo); 198{
196 BUG_ON(!list_empty(&lo->plh_layouts)); 199 if (atomic_dec_and_test(&lo->plh_refcount))
197 NFS_I(lo->plh_inode)->layout = NULL; 200 destroy_layout_hdr(lo);
198 kfree(lo);
199 }
200} 201}
201 202
202void 203void
203put_layout_hdr(struct inode *inode) 204put_layout_hdr(struct pnfs_layout_hdr *lo)
204{ 205{
205 spin_lock(&inode->i_lock); 206 struct inode *inode = lo->plh_inode;
206 put_layout_hdr_locked(NFS_I(inode)->layout); 207
207 spin_unlock(&inode->i_lock); 208 if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
209 destroy_layout_hdr(lo);
210 spin_unlock(&inode->i_lock);
211 }
208} 212}
209 213
210static void 214static void
@@ -223,7 +227,7 @@ static void free_lseg(struct pnfs_layout_segment *lseg)
223 227
224 NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg); 228 NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
225 /* Matched by get_layout_hdr in pnfs_insert_layout */ 229 /* Matched by get_layout_hdr in pnfs_insert_layout */
226 put_layout_hdr(ino); 230 put_layout_hdr(NFS_I(ino)->layout);
227} 231}
228 232
229/* The use of tmp_list is necessary because pnfs_curr_ld->free_lseg 233/* The use of tmp_list is necessary because pnfs_curr_ld->free_lseg
@@ -490,7 +494,7 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
490 __func__, lseg, lseg->pls_range.iomode, 494 __func__, lseg, lseg->pls_range.iomode,
491 lseg->pls_range.offset, lseg->pls_range.length); 495 lseg->pls_range.offset, lseg->pls_range.length);
492 } 496 }
493 get_layout_hdr_locked(lo); 497 get_layout_hdr(lo);
494 498
495 dprintk("%s:Return\n", __func__); 499 dprintk("%s:Return\n", __func__);
496} 500}
@@ -503,7 +507,7 @@ alloc_init_layout_hdr(struct inode *ino)
503 lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL); 507 lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL);
504 if (!lo) 508 if (!lo)
505 return NULL; 509 return NULL;
506 lo->plh_refcount = 1; 510 atomic_set(&lo->plh_refcount, 1);
507 INIT_LIST_HEAD(&lo->plh_layouts); 511 INIT_LIST_HEAD(&lo->plh_layouts);
508 INIT_LIST_HEAD(&lo->plh_segs); 512 INIT_LIST_HEAD(&lo->plh_segs);
509 lo->plh_inode = ino; 513 lo->plh_inode = ino;
@@ -618,7 +622,7 @@ pnfs_update_layout(struct inode *ino,
618 goto out_unlock; 622 goto out_unlock;
619 atomic_inc(&lo->plh_outstanding); 623 atomic_inc(&lo->plh_outstanding);
620 624
621 get_layout_hdr_locked(lo); 625 get_layout_hdr(lo);
622 if (list_empty(&lo->plh_segs)) { 626 if (list_empty(&lo->plh_segs)) {
623 /* The lo must be on the clp list if there is any 627 /* The lo must be on the clp list if there is any
624 * chance of a CB_LAYOUTRECALL(FILE) coming in. 628 * chance of a CB_LAYOUTRECALL(FILE) coming in.
@@ -641,7 +645,7 @@ pnfs_update_layout(struct inode *ino,
641 spin_unlock(&ino->i_lock); 645 spin_unlock(&ino->i_lock);
642 } 646 }
643 atomic_dec(&lo->plh_outstanding); 647 atomic_dec(&lo->plh_outstanding);
644 put_layout_hdr(ino); 648 put_layout_hdr(lo);
645out: 649out:
646 dprintk("%s end, state 0x%lx lseg %p\n", __func__, 650 dprintk("%s end, state 0x%lx lseg %p\n", __func__,
647 nfsi->layout->plh_flags, lseg); 651 nfsi->layout->plh_flags, lseg);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 698380da24cc..8aaab56b794f 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -65,7 +65,7 @@ struct pnfs_layoutdriver_type {
65}; 65};
66 66
67struct pnfs_layout_hdr { 67struct pnfs_layout_hdr {
68 unsigned long plh_refcount; 68 atomic_t plh_refcount;
69 struct list_head plh_layouts; /* other client layouts */ 69 struct list_head plh_layouts; /* other client layouts */
70 struct list_head plh_segs; /* layout segments list */ 70 struct list_head plh_segs; /* layout segments list */
71 nfs4_stateid plh_stateid; 71 nfs4_stateid plh_stateid;
@@ -147,7 +147,7 @@ void unset_pnfs_layoutdriver(struct nfs_server *);
147int pnfs_layout_process(struct nfs4_layoutget *lgp); 147int pnfs_layout_process(struct nfs4_layoutget *lgp);
148void pnfs_destroy_layout(struct nfs_inode *); 148void pnfs_destroy_layout(struct nfs_inode *);
149void pnfs_destroy_all_layouts(struct nfs_client *); 149void pnfs_destroy_all_layouts(struct nfs_client *);
150void put_layout_hdr(struct inode *inode); 150void put_layout_hdr(struct pnfs_layout_hdr *lo);
151int pnfs_choose_layoutget_stateid(nfs4_stateid *dst, 151int pnfs_choose_layoutget_stateid(nfs4_stateid *dst,
152 struct pnfs_layout_hdr *lo, 152 struct pnfs_layout_hdr *lo,
153 struct nfs4_state *open_state); 153 struct nfs4_state *open_state);