aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-05-02 20:36:10 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-05-03 16:46:13 -0400
commit9c8c10e262e0f62cb2530f1b076de979123183dd (patch)
tree36bc489a0f5a8e5baa1568f12e0aa761f8abb308
parentfe91522a7ba82ca1a51b07e19954b3825e4aaa22 (diff)
more graceful recovery in umount_collect()
Start with shrink_dcache_parent(), then scan what remains. First of all, BUG() is very much an overkill here; we are holding ->s_umount, and hitting BUG() means that a lot of interesting stuff will be hanging after that point (sync(2), for example). Moreover, in cases when there had been more than one leak, we'll be better off reporting all of them. And more than just the last component of pathname - %pd is there for just such uses... That was the last user of dentry_lru_del(), so kill it off... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/dcache.c101
1 files changed, 25 insertions, 76 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index f39a6f5a1220..2321e1a861f6 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -395,22 +395,6 @@ static void dentry_lru_add(struct dentry *dentry)
395 d_lru_add(dentry); 395 d_lru_add(dentry);
396} 396}
397 397
398/*
399 * Remove a dentry with references from the LRU.
400 *
401 * If we are on the shrink list, then we can get to try_prune_one_dentry() and
402 * lose our last reference through the parent walk. In this case, we need to
403 * remove ourselves from the shrink list, not the LRU.
404 */
405static void dentry_lru_del(struct dentry *dentry)
406{
407 if (dentry->d_flags & DCACHE_LRU_LIST) {
408 if (dentry->d_flags & DCACHE_SHRINK_LIST)
409 return d_shrink_del(dentry);
410 d_lru_del(dentry);
411 }
412}
413
414/** 398/**
415 * d_drop - drop a dentry 399 * d_drop - drop a dentry
416 * @dentry: dentry to drop 400 * @dentry: dentry to drop
@@ -1275,45 +1259,35 @@ void shrink_dcache_parent(struct dentry *parent)
1275} 1259}
1276EXPORT_SYMBOL(shrink_dcache_parent); 1260EXPORT_SYMBOL(shrink_dcache_parent);
1277 1261
1278static enum d_walk_ret umount_collect(void *_data, struct dentry *dentry) 1262static enum d_walk_ret umount_check(void *_data, struct dentry *dentry)
1279{ 1263{
1280 struct select_data *data = _data; 1264 /* it has busy descendents; complain about those instead */
1281 enum d_walk_ret ret = D_WALK_CONTINUE; 1265 if (!list_empty(&dentry->d_subdirs))
1266 return D_WALK_CONTINUE;
1282 1267
1283 if (dentry->d_lockref.count) { 1268 /* root with refcount 1 is fine */
1284 dentry_lru_del(dentry); 1269 if (dentry == _data && dentry->d_lockref.count == 1)
1285 if (likely(!list_empty(&dentry->d_subdirs))) 1270 return D_WALK_CONTINUE;
1286 goto out; 1271
1287 if (dentry == data->start && dentry->d_lockref.count == 1) 1272 printk(KERN_ERR "BUG: Dentry %p{i=%lx,n=%pd} "
1288 goto out; 1273 " still in use (%d) [unmount of %s %s]\n",
1289 printk(KERN_ERR
1290 "BUG: Dentry %p{i=%lx,n=%s}"
1291 " still in use (%d)"
1292 " [unmount of %s %s]\n",
1293 dentry, 1274 dentry,
1294 dentry->d_inode ? 1275 dentry->d_inode ?
1295 dentry->d_inode->i_ino : 0UL, 1276 dentry->d_inode->i_ino : 0UL,
1296 dentry->d_name.name, 1277 dentry,
1297 dentry->d_lockref.count, 1278 dentry->d_lockref.count,
1298 dentry->d_sb->s_type->name, 1279 dentry->d_sb->s_type->name,
1299 dentry->d_sb->s_id); 1280 dentry->d_sb->s_id);
1300 BUG(); 1281 WARN_ON(1);
1301 } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { 1282 return D_WALK_CONTINUE;
1302 /* 1283}
1303 * We can't use d_lru_shrink_move() because we 1284
1304 * need to get the global LRU lock and do the 1285static void do_one_tree(struct dentry *dentry)
1305 * LRU accounting. 1286{
1306 */ 1287 shrink_dcache_parent(dentry);
1307 if (dentry->d_flags & DCACHE_LRU_LIST) 1288 d_walk(dentry, dentry, umount_check, NULL);
1308 d_lru_del(dentry); 1289 d_drop(dentry);
1309 d_shrink_add(dentry, &data->dispose); 1290 dput(dentry);
1310 data->found++;
1311 ret = D_WALK_NORETRY;
1312 }
1313out:
1314 if (data->found && need_resched())
1315 ret = D_WALK_QUIT;
1316 return ret;
1317} 1291}
1318 1292
1319/* 1293/*
@@ -1323,40 +1297,15 @@ void shrink_dcache_for_umount(struct super_block *sb)
1323{ 1297{
1324 struct dentry *dentry; 1298 struct dentry *dentry;
1325 1299
1326 if (down_read_trylock(&sb->s_umount)) 1300 WARN(down_read_trylock(&sb->s_umount), "s_umount should've been locked");
1327 BUG();
1328 1301
1329 dentry = sb->s_root; 1302 dentry = sb->s_root;
1330 sb->s_root = NULL; 1303 sb->s_root = NULL;
1331 for (;;) { 1304 do_one_tree(dentry);
1332 struct select_data data;
1333
1334 INIT_LIST_HEAD(&data.dispose);
1335 data.start = dentry;
1336 data.found = 0;
1337
1338 d_walk(dentry, &data, umount_collect, NULL);
1339 if (!data.found)
1340 break;
1341
1342 shrink_dentry_list(&data.dispose);
1343 cond_resched();
1344 }
1345 d_drop(dentry);
1346 dput(dentry);
1347 1305
1348 while (!hlist_bl_empty(&sb->s_anon)) { 1306 while (!hlist_bl_empty(&sb->s_anon)) {
1349 struct select_data data; 1307 dentry = dget(hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash));
1350 dentry = hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash); 1308 do_one_tree(dentry);
1351
1352 INIT_LIST_HEAD(&data.dispose);
1353 data.start = NULL;
1354 data.found = 0;
1355
1356 d_walk(dentry, &data, umount_collect, NULL);
1357 if (data.found)
1358 shrink_dentry_list(&data.dispose);
1359 cond_resched();
1360 } 1309 }
1361} 1310}
1362 1311