diff options
author | Weston Andros Adamson <dros@netapp.com> | 2011-05-31 21:46:50 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-06-15 11:23:02 -0400 |
commit | 9e3bd4e24e94d60d2e0762e919aab6c9a7fc0c5b (patch) | |
tree | 61ac70f49e793494dee1196dae55ac0c19036410 | |
parent | 3f303103b884ca577908d3e5c0650ad12e40c586 (diff) |
NFS: fix umount of pnfs filesystems
Unmounting a pnfs filesystem hangs using filelayout and possibly others.
This fixes the use of the rcu protected node by making use of a new 'tmpnode'
for the temporary purge list. Also, the spinlock shouldn't be held when calling
synchronize_rcu().
Signed-off-by: Weston Andros Adamson <dros@netapp.com>
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/pnfs.h | 1 | ||||
-rw-r--r-- | fs/nfs/pnfs_dev.c | 16 |
2 files changed, 12 insertions, 5 deletions
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 48d0a8e4d062..96bf4e6f45be 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -186,6 +186,7 @@ int pnfs_ld_read_done(struct nfs_read_data *); | |||
186 | /* pnfs_dev.c */ | 186 | /* pnfs_dev.c */ |
187 | struct nfs4_deviceid_node { | 187 | struct nfs4_deviceid_node { |
188 | struct hlist_node node; | 188 | struct hlist_node node; |
189 | struct hlist_node tmpnode; | ||
189 | const struct pnfs_layoutdriver_type *ld; | 190 | const struct pnfs_layoutdriver_type *ld; |
190 | const struct nfs_client *nfs_client; | 191 | const struct nfs_client *nfs_client; |
191 | struct nfs4_deviceid deviceid; | 192 | struct nfs4_deviceid deviceid; |
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c index c65e133ce9c0..5944d4b369a2 100644 --- a/fs/nfs/pnfs_dev.c +++ b/fs/nfs/pnfs_dev.c | |||
@@ -174,6 +174,7 @@ nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, | |||
174 | const struct nfs4_deviceid *id) | 174 | const struct nfs4_deviceid *id) |
175 | { | 175 | { |
176 | INIT_HLIST_NODE(&d->node); | 176 | INIT_HLIST_NODE(&d->node); |
177 | INIT_HLIST_NODE(&d->tmpnode); | ||
177 | d->ld = ld; | 178 | d->ld = ld; |
178 | d->nfs_client = nfs_client; | 179 | d->nfs_client = nfs_client; |
179 | d->deviceid = *id; | 180 | d->deviceid = *id; |
@@ -238,24 +239,29 @@ static void | |||
238 | _deviceid_purge_client(const struct nfs_client *clp, long hash) | 239 | _deviceid_purge_client(const struct nfs_client *clp, long hash) |
239 | { | 240 | { |
240 | struct nfs4_deviceid_node *d; | 241 | struct nfs4_deviceid_node *d; |
241 | struct hlist_node *n, *next; | 242 | struct hlist_node *n; |
242 | HLIST_HEAD(tmp); | 243 | HLIST_HEAD(tmp); |
243 | 244 | ||
245 | spin_lock(&nfs4_deviceid_lock); | ||
244 | rcu_read_lock(); | 246 | rcu_read_lock(); |
245 | hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) | 247 | hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) |
246 | if (d->nfs_client == clp && atomic_read(&d->ref)) { | 248 | if (d->nfs_client == clp && atomic_read(&d->ref)) { |
247 | hlist_del_init_rcu(&d->node); | 249 | hlist_del_init_rcu(&d->node); |
248 | hlist_add_head(&d->node, &tmp); | 250 | hlist_add_head(&d->tmpnode, &tmp); |
249 | } | 251 | } |
250 | rcu_read_unlock(); | 252 | rcu_read_unlock(); |
253 | spin_unlock(&nfs4_deviceid_lock); | ||
251 | 254 | ||
252 | if (hlist_empty(&tmp)) | 255 | if (hlist_empty(&tmp)) |
253 | return; | 256 | return; |
254 | 257 | ||
255 | synchronize_rcu(); | 258 | synchronize_rcu(); |
256 | hlist_for_each_entry_safe(d, n, next, &tmp, node) | 259 | while (!hlist_empty(&tmp)) { |
260 | d = hlist_entry(tmp.first, struct nfs4_deviceid_node, tmpnode); | ||
261 | hlist_del(&d->tmpnode); | ||
257 | if (atomic_dec_and_test(&d->ref)) | 262 | if (atomic_dec_and_test(&d->ref)) |
258 | d->ld->free_deviceid_node(d); | 263 | d->ld->free_deviceid_node(d); |
264 | } | ||
259 | } | 265 | } |
260 | 266 | ||
261 | void | 267 | void |
@@ -263,8 +269,8 @@ nfs4_deviceid_purge_client(const struct nfs_client *clp) | |||
263 | { | 269 | { |
264 | long h; | 270 | long h; |
265 | 271 | ||
266 | spin_lock(&nfs4_deviceid_lock); | 272 | if (!(clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_MDS)) |
273 | return; | ||
267 | for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++) | 274 | for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++) |
268 | _deviceid_purge_client(clp, h); | 275 | _deviceid_purge_client(clp, h); |
269 | spin_unlock(&nfs4_deviceid_lock); | ||
270 | } | 276 | } |