diff options
author | Fred Isaman <iisaman@netapp.com> | 2011-02-28 20:34:13 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-11 15:38:42 -0500 |
commit | d684d2ae10a4f95d3035abf698d7d611ff2cd279 (patch) | |
tree | 9bae2d1808b8e2a0d153d8d1d13f0d9a01408de0 /fs | |
parent | 94de8b27d0dcb2608d56a7e5c2941b87e6da7ce3 (diff) |
NFSv4.1: lseg refcounting
Prepare put_lseg and get_lseg to be called from the pNFS I/O code.
Pull common code from pnfs_lseg_locked to call from pnfs_lseg.
Inline pnfs_lseg_locked into it's only caller.
Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/pnfs.c | 62 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 20 |
2 files changed, 59 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) { |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index e2612ea0cbed..9a994bc9899f 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -177,6 +177,16 @@ static inline int lo_fail_bit(u32 iomode) | |||
177 | NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED; | 177 | NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED; |
178 | } | 178 | } |
179 | 179 | ||
180 | static inline struct pnfs_layout_segment * | ||
181 | get_lseg(struct pnfs_layout_segment *lseg) | ||
182 | { | ||
183 | if (lseg) { | ||
184 | atomic_inc(&lseg->pls_refcount); | ||
185 | smp_mb__after_atomic_inc(); | ||
186 | } | ||
187 | return lseg; | ||
188 | } | ||
189 | |||
180 | /* Return true if a layout driver is being used for this mountpoint */ | 190 | /* Return true if a layout driver is being used for this mountpoint */ |
181 | static inline int pnfs_enabled_sb(struct nfs_server *nfss) | 191 | static inline int pnfs_enabled_sb(struct nfs_server *nfss) |
182 | { | 192 | { |
@@ -194,6 +204,16 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi) | |||
194 | } | 204 | } |
195 | 205 | ||
196 | static inline struct pnfs_layout_segment * | 206 | static inline struct pnfs_layout_segment * |
207 | get_lseg(struct pnfs_layout_segment *lseg) | ||
208 | { | ||
209 | return NULL; | ||
210 | } | ||
211 | |||
212 | static inline void put_lseg(struct pnfs_layout_segment *lseg) | ||
213 | { | ||
214 | } | ||
215 | |||
216 | static inline struct pnfs_layout_segment * | ||
197 | pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, | 217 | pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, |
198 | enum pnfs_iomode access_type) | 218 | enum pnfs_iomode access_type) |
199 | { | 219 | { |