aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@netapp.com>2011-05-31 21:46:50 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-06-15 11:23:02 -0400
commit9e3bd4e24e94d60d2e0762e919aab6c9a7fc0c5b (patch)
tree61ac70f49e793494dee1196dae55ac0c19036410
parent3f303103b884ca577908d3e5c0650ad12e40c586 (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.h1
-rw-r--r--fs/nfs/pnfs_dev.c16
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 */
187struct nfs4_deviceid_node { 187struct 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
261void 267void
@@ -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}