aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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