diff options
-rw-r--r-- | fs/dcache.c | 101 |
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 | */ | ||
405 | static 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 | } |
1276 | EXPORT_SYMBOL(shrink_dcache_parent); | 1260 | EXPORT_SYMBOL(shrink_dcache_parent); |
1277 | 1261 | ||
1278 | static enum d_walk_ret umount_collect(void *_data, struct dentry *dentry) | 1262 | static 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 | 1285 | static 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 | } | ||
1313 | out: | ||
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 | ||