.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * fs/dcache.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
27 | 28 | #include <linux/export.h> |
---|
28 | 29 | #include <linux/security.h> |
---|
29 | 30 | #include <linux/seqlock.h> |
---|
30 | | -#include <linux/bootmem.h> |
---|
| 31 | +#include <linux/memblock.h> |
---|
31 | 32 | #include <linux/bit_spinlock.h> |
---|
32 | 33 | #include <linux/rculist_bl.h> |
---|
33 | 34 | #include <linux/list_lru.h> |
---|
.. | .. |
---|
120 | 121 | |
---|
121 | 122 | static DEFINE_PER_CPU(long, nr_dentry); |
---|
122 | 123 | static DEFINE_PER_CPU(long, nr_dentry_unused); |
---|
| 124 | +static DEFINE_PER_CPU(long, nr_dentry_negative); |
---|
123 | 125 | |
---|
124 | 126 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) |
---|
125 | 127 | |
---|
.. | .. |
---|
153 | 155 | return sum < 0 ? 0 : sum; |
---|
154 | 156 | } |
---|
155 | 157 | |
---|
156 | | -int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, |
---|
| 158 | +static long get_nr_dentry_negative(void) |
---|
| 159 | +{ |
---|
| 160 | + int i; |
---|
| 161 | + long sum = 0; |
---|
| 162 | + |
---|
| 163 | + for_each_possible_cpu(i) |
---|
| 164 | + sum += per_cpu(nr_dentry_negative, i); |
---|
| 165 | + return sum < 0 ? 0 : sum; |
---|
| 166 | +} |
---|
| 167 | + |
---|
| 168 | +int proc_nr_dentry(struct ctl_table *table, int write, void *buffer, |
---|
157 | 169 | size_t *lenp, loff_t *ppos) |
---|
158 | 170 | { |
---|
159 | 171 | dentry_stat.nr_dentry = get_nr_dentry(); |
---|
160 | 172 | dentry_stat.nr_unused = get_nr_dentry_unused(); |
---|
| 173 | + dentry_stat.nr_negative = get_nr_dentry_negative(); |
---|
161 | 174 | return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); |
---|
162 | 175 | } |
---|
163 | 176 | #endif |
---|
.. | .. |
---|
273 | 286 | void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) |
---|
274 | 287 | { |
---|
275 | 288 | spin_lock(&dentry->d_lock); |
---|
| 289 | + name->name = dentry->d_name; |
---|
276 | 290 | if (unlikely(dname_external(dentry))) { |
---|
277 | | - struct external_name *p = external_name(dentry); |
---|
278 | | - atomic_inc(&p->u.count); |
---|
279 | | - spin_unlock(&dentry->d_lock); |
---|
280 | | - name->name = p->name; |
---|
| 291 | + atomic_inc(&external_name(dentry)->u.count); |
---|
281 | 292 | } else { |
---|
282 | 293 | memcpy(name->inline_name, dentry->d_iname, |
---|
283 | 294 | dentry->d_name.len + 1); |
---|
284 | | - spin_unlock(&dentry->d_lock); |
---|
285 | | - name->name = name->inline_name; |
---|
| 295 | + name->name.name = name->inline_name; |
---|
286 | 296 | } |
---|
| 297 | + spin_unlock(&dentry->d_lock); |
---|
287 | 298 | } |
---|
288 | 299 | EXPORT_SYMBOL(take_dentry_name_snapshot); |
---|
289 | 300 | |
---|
290 | 301 | void release_dentry_name_snapshot(struct name_snapshot *name) |
---|
291 | 302 | { |
---|
292 | | - if (unlikely(name->name != name->inline_name)) { |
---|
| 303 | + if (unlikely(name->name.name != name->inline_name)) { |
---|
293 | 304 | struct external_name *p; |
---|
294 | | - p = container_of(name->name, struct external_name, name[0]); |
---|
| 305 | + p = container_of(name->name.name, struct external_name, name[0]); |
---|
295 | 306 | if (unlikely(atomic_dec_and_test(&p->u.count))) |
---|
296 | 307 | kfree_rcu(p, u.head); |
---|
297 | 308 | } |
---|
.. | .. |
---|
308 | 319 | flags = READ_ONCE(dentry->d_flags); |
---|
309 | 320 | flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); |
---|
310 | 321 | flags |= type_flags; |
---|
311 | | - WRITE_ONCE(dentry->d_flags, flags); |
---|
| 322 | + smp_store_release(&dentry->d_flags, flags); |
---|
312 | 323 | } |
---|
313 | 324 | |
---|
314 | 325 | static inline void __d_clear_type_and_inode(struct dentry *dentry) |
---|
.. | .. |
---|
318 | 329 | flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); |
---|
319 | 330 | WRITE_ONCE(dentry->d_flags, flags); |
---|
320 | 331 | dentry->d_inode = NULL; |
---|
| 332 | + if (dentry->d_flags & DCACHE_LRU_LIST) |
---|
| 333 | + this_cpu_inc(nr_dentry_negative); |
---|
321 | 334 | } |
---|
322 | 335 | |
---|
323 | 336 | static void dentry_free(struct dentry *dentry) |
---|
.. | .. |
---|
372 | 385 | * The per-cpu "nr_dentry_unused" counters are updated with |
---|
373 | 386 | * the DCACHE_LRU_LIST bit. |
---|
374 | 387 | * |
---|
| 388 | + * The per-cpu "nr_dentry_negative" counters are only updated |
---|
| 389 | + * when deleted from or added to the per-superblock LRU list, not |
---|
| 390 | + * from/to the shrink list. That is to avoid an unneeded dec/inc |
---|
| 391 | + * pair when moving from LRU to shrink list in select_collect(). |
---|
| 392 | + * |
---|
375 | 393 | * These helper functions make sure we always follow the |
---|
376 | 394 | * rules. d_lock must be held by the caller. |
---|
377 | 395 | */ |
---|
.. | .. |
---|
381 | 399 | D_FLAG_VERIFY(dentry, 0); |
---|
382 | 400 | dentry->d_flags |= DCACHE_LRU_LIST; |
---|
383 | 401 | this_cpu_inc(nr_dentry_unused); |
---|
| 402 | + if (d_is_negative(dentry)) |
---|
| 403 | + this_cpu_inc(nr_dentry_negative); |
---|
384 | 404 | WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); |
---|
385 | 405 | } |
---|
386 | 406 | |
---|
.. | .. |
---|
389 | 409 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); |
---|
390 | 410 | dentry->d_flags &= ~DCACHE_LRU_LIST; |
---|
391 | 411 | this_cpu_dec(nr_dentry_unused); |
---|
| 412 | + if (d_is_negative(dentry)) |
---|
| 413 | + this_cpu_dec(nr_dentry_negative); |
---|
392 | 414 | WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); |
---|
393 | 415 | } |
---|
394 | 416 | |
---|
.. | .. |
---|
419 | 441 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); |
---|
420 | 442 | dentry->d_flags &= ~DCACHE_LRU_LIST; |
---|
421 | 443 | this_cpu_dec(nr_dentry_unused); |
---|
| 444 | + if (d_is_negative(dentry)) |
---|
| 445 | + this_cpu_dec(nr_dentry_negative); |
---|
422 | 446 | list_lru_isolate(lru, &dentry->d_lru); |
---|
423 | 447 | } |
---|
424 | 448 | |
---|
.. | .. |
---|
427 | 451 | { |
---|
428 | 452 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); |
---|
429 | 453 | dentry->d_flags |= DCACHE_SHRINK_LIST; |
---|
| 454 | + if (d_is_negative(dentry)) |
---|
| 455 | + this_cpu_dec(nr_dentry_negative); |
---|
430 | 456 | list_lru_isolate_move(lru, &dentry->d_lru, list); |
---|
431 | 457 | } |
---|
432 | 458 | |
---|
.. | .. |
---|
621 | 647 | if (dentry->d_op->d_delete(dentry)) |
---|
622 | 648 | return false; |
---|
623 | 649 | } |
---|
| 650 | + |
---|
| 651 | + if (unlikely(dentry->d_flags & DCACHE_DONTCACHE)) |
---|
| 652 | + return false; |
---|
| 653 | + |
---|
624 | 654 | /* retain; LRU fodder */ |
---|
625 | 655 | dentry->d_lockref.count--; |
---|
626 | 656 | if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) |
---|
.. | .. |
---|
629 | 659 | dentry->d_flags |= DCACHE_REFERENCED; |
---|
630 | 660 | return true; |
---|
631 | 661 | } |
---|
| 662 | + |
---|
| 663 | +void d_mark_dontcache(struct inode *inode) |
---|
| 664 | +{ |
---|
| 665 | + struct dentry *de; |
---|
| 666 | + |
---|
| 667 | + spin_lock(&inode->i_lock); |
---|
| 668 | + hlist_for_each_entry(de, &inode->i_dentry, d_u.d_alias) { |
---|
| 669 | + spin_lock(&de->d_lock); |
---|
| 670 | + de->d_flags |= DCACHE_DONTCACHE; |
---|
| 671 | + spin_unlock(&de->d_lock); |
---|
| 672 | + } |
---|
| 673 | + inode->i_state |= I_DONTCACHE; |
---|
| 674 | + spin_unlock(&inode->i_lock); |
---|
| 675 | +} |
---|
| 676 | +EXPORT_SYMBOL(d_mark_dontcache); |
---|
632 | 677 | |
---|
633 | 678 | /* |
---|
634 | 679 | * Finish off a dentry we've decided to kill. |
---|
.. | .. |
---|
835 | 880 | } |
---|
836 | 881 | EXPORT_SYMBOL(dput); |
---|
837 | 882 | |
---|
| 883 | +static void __dput_to_list(struct dentry *dentry, struct list_head *list) |
---|
| 884 | +__must_hold(&dentry->d_lock) |
---|
| 885 | +{ |
---|
| 886 | + if (dentry->d_flags & DCACHE_SHRINK_LIST) { |
---|
| 887 | + /* let the owner of the list it's on deal with it */ |
---|
| 888 | + --dentry->d_lockref.count; |
---|
| 889 | + } else { |
---|
| 890 | + if (dentry->d_flags & DCACHE_LRU_LIST) |
---|
| 891 | + d_lru_del(dentry); |
---|
| 892 | + if (!--dentry->d_lockref.count) |
---|
| 893 | + d_shrink_add(dentry, list); |
---|
| 894 | + } |
---|
| 895 | +} |
---|
| 896 | + |
---|
| 897 | +void dput_to_list(struct dentry *dentry, struct list_head *list) |
---|
| 898 | +{ |
---|
| 899 | + rcu_read_lock(); |
---|
| 900 | + if (likely(fast_dput(dentry))) { |
---|
| 901 | + rcu_read_unlock(); |
---|
| 902 | + return; |
---|
| 903 | + } |
---|
| 904 | + rcu_read_unlock(); |
---|
| 905 | + if (!retain_dentry(dentry)) |
---|
| 906 | + __dput_to_list(dentry, list); |
---|
| 907 | + spin_unlock(&dentry->d_lock); |
---|
| 908 | +} |
---|
838 | 909 | |
---|
839 | 910 | /* This must be called with d_lock held */ |
---|
840 | 911 | static inline void __dget_dlock(struct dentry *dentry) |
---|
.. | .. |
---|
1043 | 1114 | return false; |
---|
1044 | 1115 | } |
---|
1045 | 1116 | |
---|
1046 | | -static void shrink_dentry_list(struct list_head *list) |
---|
| 1117 | +void shrink_dentry_list(struct list_head *list) |
---|
1047 | 1118 | { |
---|
1048 | 1119 | while (!list_empty(list)) { |
---|
1049 | 1120 | struct dentry *dentry, *parent; |
---|
.. | .. |
---|
1065 | 1136 | rcu_read_unlock(); |
---|
1066 | 1137 | d_shrink_del(dentry); |
---|
1067 | 1138 | parent = dentry->d_parent; |
---|
| 1139 | + if (parent != dentry) |
---|
| 1140 | + __dput_to_list(parent, list); |
---|
1068 | 1141 | __dentry_kill(dentry); |
---|
1069 | | - if (parent == dentry) |
---|
1070 | | - continue; |
---|
1071 | | - /* |
---|
1072 | | - * We need to prune ancestors too. This is necessary to prevent |
---|
1073 | | - * quadratic behavior of shrink_dcache_parent(), but is also |
---|
1074 | | - * expected to be beneficial in reducing dentry cache |
---|
1075 | | - * fragmentation. |
---|
1076 | | - */ |
---|
1077 | | - dentry = parent; |
---|
1078 | | - while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) |
---|
1079 | | - dentry = dentry_kill(dentry); |
---|
1080 | 1142 | } |
---|
1081 | 1143 | } |
---|
1082 | 1144 | |
---|
.. | .. |
---|
1278 | 1340 | |
---|
1279 | 1341 | if (!list_empty(&dentry->d_subdirs)) { |
---|
1280 | 1342 | spin_unlock(&this_parent->d_lock); |
---|
1281 | | - spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); |
---|
| 1343 | + spin_release(&dentry->d_lock.dep_map, _RET_IP_); |
---|
1282 | 1344 | this_parent = dentry; |
---|
1283 | 1345 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); |
---|
1284 | 1346 | goto repeat; |
---|
.. | .. |
---|
1421 | 1483 | |
---|
1422 | 1484 | struct select_data { |
---|
1423 | 1485 | struct dentry *start; |
---|
| 1486 | + union { |
---|
| 1487 | + long found; |
---|
| 1488 | + struct dentry *victim; |
---|
| 1489 | + }; |
---|
1424 | 1490 | struct list_head dispose; |
---|
1425 | | - int found; |
---|
1426 | 1491 | }; |
---|
1427 | 1492 | |
---|
1428 | 1493 | static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) |
---|
.. | .. |
---|
1454 | 1519 | return ret; |
---|
1455 | 1520 | } |
---|
1456 | 1521 | |
---|
| 1522 | +static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry) |
---|
| 1523 | +{ |
---|
| 1524 | + struct select_data *data = _data; |
---|
| 1525 | + enum d_walk_ret ret = D_WALK_CONTINUE; |
---|
| 1526 | + |
---|
| 1527 | + if (data->start == dentry) |
---|
| 1528 | + goto out; |
---|
| 1529 | + |
---|
| 1530 | + if (dentry->d_flags & DCACHE_SHRINK_LIST) { |
---|
| 1531 | + if (!dentry->d_lockref.count) { |
---|
| 1532 | + rcu_read_lock(); |
---|
| 1533 | + data->victim = dentry; |
---|
| 1534 | + return D_WALK_QUIT; |
---|
| 1535 | + } |
---|
| 1536 | + } else { |
---|
| 1537 | + if (dentry->d_flags & DCACHE_LRU_LIST) |
---|
| 1538 | + d_lru_del(dentry); |
---|
| 1539 | + if (!dentry->d_lockref.count) |
---|
| 1540 | + d_shrink_add(dentry, &data->dispose); |
---|
| 1541 | + } |
---|
| 1542 | + /* |
---|
| 1543 | + * We can return to the caller if we have found some (this |
---|
| 1544 | + * ensures forward progress). We'll be coming back to find |
---|
| 1545 | + * the rest. |
---|
| 1546 | + */ |
---|
| 1547 | + if (!list_empty(&data->dispose)) |
---|
| 1548 | + ret = need_resched() ? D_WALK_QUIT : D_WALK_NORETRY; |
---|
| 1549 | +out: |
---|
| 1550 | + return ret; |
---|
| 1551 | +} |
---|
| 1552 | + |
---|
1457 | 1553 | /** |
---|
1458 | 1554 | * shrink_dcache_parent - prune dcache |
---|
1459 | 1555 | * @parent: parent of entries to prune |
---|
.. | .. |
---|
1463 | 1559 | void shrink_dcache_parent(struct dentry *parent) |
---|
1464 | 1560 | { |
---|
1465 | 1561 | for (;;) { |
---|
1466 | | - struct select_data data; |
---|
| 1562 | + struct select_data data = {.start = parent}; |
---|
1467 | 1563 | |
---|
1468 | 1564 | INIT_LIST_HEAD(&data.dispose); |
---|
1469 | | - data.start = parent; |
---|
1470 | | - data.found = 0; |
---|
1471 | | - |
---|
1472 | 1565 | d_walk(parent, &data, select_collect); |
---|
1473 | 1566 | |
---|
1474 | 1567 | if (!list_empty(&data.dispose)) { |
---|
.. | .. |
---|
1479 | 1572 | cond_resched(); |
---|
1480 | 1573 | if (!data.found) |
---|
1481 | 1574 | break; |
---|
| 1575 | + data.victim = NULL; |
---|
| 1576 | + d_walk(parent, &data, select_collect2); |
---|
| 1577 | + if (data.victim) { |
---|
| 1578 | + struct dentry *parent; |
---|
| 1579 | + spin_lock(&data.victim->d_lock); |
---|
| 1580 | + if (!shrink_lock_dentry(data.victim)) { |
---|
| 1581 | + spin_unlock(&data.victim->d_lock); |
---|
| 1582 | + rcu_read_unlock(); |
---|
| 1583 | + } else { |
---|
| 1584 | + rcu_read_unlock(); |
---|
| 1585 | + parent = data.victim->d_parent; |
---|
| 1586 | + if (parent != data.victim) |
---|
| 1587 | + __dput_to_list(parent, &data.dispose); |
---|
| 1588 | + __dentry_kill(data.victim); |
---|
| 1589 | + } |
---|
| 1590 | + } |
---|
| 1591 | + if (!list_empty(&data.dispose)) |
---|
| 1592 | + shrink_dentry_list(&data.dispose); |
---|
1482 | 1593 | } |
---|
1483 | 1594 | } |
---|
1484 | 1595 | EXPORT_SYMBOL(shrink_dcache_parent); |
---|
.. | .. |
---|
1589 | 1700 | * copied and the copy passed in may be reused after this call. |
---|
1590 | 1701 | */ |
---|
1591 | 1702 | |
---|
1592 | | -struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) |
---|
| 1703 | +static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) |
---|
1593 | 1704 | { |
---|
1594 | 1705 | struct dentry *dentry; |
---|
1595 | 1706 | char *dname; |
---|
.. | .. |
---|
1635 | 1746 | dentry->d_lockref.count = 1; |
---|
1636 | 1747 | dentry->d_flags = 0; |
---|
1637 | 1748 | spin_lock_init(&dentry->d_lock); |
---|
1638 | | - seqcount_init(&dentry->d_seq); |
---|
| 1749 | + seqcount_spinlock_init(&dentry->d_seq, &dentry->d_lock); |
---|
1639 | 1750 | dentry->d_inode = NULL; |
---|
1640 | 1751 | dentry->d_parent = dentry; |
---|
1641 | 1752 | dentry->d_sb = sb; |
---|
.. | .. |
---|
1718 | 1829 | * never be anyone's children or parents. Unlike all other |
---|
1719 | 1830 | * dentries, these will not have RCU delay between dropping the |
---|
1720 | 1831 | * last reference and freeing them. |
---|
| 1832 | + * |
---|
| 1833 | + * The only user is alloc_file_pseudo() and that's what should |
---|
| 1834 | + * be considered a public interface. Don't use directly. |
---|
1721 | 1835 | */ |
---|
1722 | 1836 | struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) |
---|
1723 | 1837 | { |
---|
.. | .. |
---|
1726 | 1840 | dentry->d_flags |= DCACHE_NORCU; |
---|
1727 | 1841 | return dentry; |
---|
1728 | 1842 | } |
---|
1729 | | -EXPORT_SYMBOL(d_alloc_pseudo); |
---|
1730 | 1843 | |
---|
1731 | 1844 | struct dentry *d_alloc_name(struct dentry *parent, const char *name) |
---|
1732 | 1845 | { |
---|
.. | .. |
---|
1825 | 1938 | WARN_ON(d_in_lookup(dentry)); |
---|
1826 | 1939 | |
---|
1827 | 1940 | spin_lock(&dentry->d_lock); |
---|
| 1941 | + /* |
---|
| 1942 | + * Decrement negative dentry count if it was in the LRU list. |
---|
| 1943 | + */ |
---|
| 1944 | + if (dentry->d_flags & DCACHE_LRU_LIST) |
---|
| 1945 | + this_cpu_dec(nr_dentry_negative); |
---|
1828 | 1946 | hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); |
---|
1829 | 1947 | raw_write_seqcount_begin(&dentry->d_seq); |
---|
1830 | 1948 | __d_set_inode_and_type(dentry, inode, add_flags); |
---|
.. | .. |
---|
1992 | 2110 | { |
---|
1993 | 2111 | return __d_obtain_alias(inode, true); |
---|
1994 | 2112 | } |
---|
1995 | | -EXPORT_SYMBOL(d_obtain_alias); |
---|
| 2113 | +EXPORT_SYMBOL_NS(d_obtain_alias, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
1996 | 2114 | |
---|
1997 | 2115 | /** |
---|
1998 | 2116 | * d_obtain_root - find or allocate a dentry for a given inode |
---|
.. | .. |
---|
2066 | 2184 | } |
---|
2067 | 2185 | return found; |
---|
2068 | 2186 | } |
---|
2069 | | -EXPORT_SYMBOL(d_add_ci); |
---|
| 2187 | +EXPORT_SYMBOL_NS(d_add_ci, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
2070 | 2188 | |
---|
2071 | 2189 | |
---|
2072 | 2190 | static inline bool d_same_name(const struct dentry *dentry, |
---|
.. | .. |
---|
2341 | 2459 | void d_delete(struct dentry * dentry) |
---|
2342 | 2460 | { |
---|
2343 | 2461 | struct inode *inode = dentry->d_inode; |
---|
2344 | | - int isdir = d_is_dir(dentry); |
---|
2345 | 2462 | |
---|
2346 | 2463 | spin_lock(&inode->i_lock); |
---|
2347 | 2464 | spin_lock(&dentry->d_lock); |
---|
.. | .. |
---|
2356 | 2473 | spin_unlock(&dentry->d_lock); |
---|
2357 | 2474 | spin_unlock(&inode->i_lock); |
---|
2358 | 2475 | } |
---|
2359 | | - fsnotify_nameremove(dentry, isdir); |
---|
2360 | 2476 | } |
---|
2361 | 2477 | EXPORT_SYMBOL(d_delete); |
---|
2362 | 2478 | |
---|
.. | .. |
---|
2949 | 3065 | __d_add(dentry, inode); |
---|
2950 | 3066 | return NULL; |
---|
2951 | 3067 | } |
---|
2952 | | -EXPORT_SYMBOL(d_splice_alias); |
---|
| 3068 | +EXPORT_SYMBOL_NS(d_splice_alias, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
2953 | 3069 | |
---|
2954 | 3070 | /* |
---|
2955 | 3071 | * Test whether new_dentry is a subdirectory of old_dentry. |
---|