diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-23 22:42:09 +0100 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-23 22:42:09 +0100 |
commit | 12cbfd0a3c52a52c2948c91b9e62e73c468d1572 (patch) | |
tree | 9252b3929159a83fc81ca0a48706bfa959660967 /fs/dcache.c | |
parent | [media] rc: Add support for decoding Sanyo protocol (diff) | |
parent | Linux 3.2-rc2 (diff) | |
download | linux-12cbfd0a3c52a52c2948c91b9e62e73c468d1572.tar.xz linux-12cbfd0a3c52a52c2948c91b9e62e73c468d1572.zip |
Merge tag 'v3.2-rc2' into staging/for_v3.3
* tag 'v3.2-rc2': (3068 commits)
Linux 3.2-rc2
hfs: add sanity check for file name length
fsl-rio: fix compile error
blackfin: Fixup export.h includes
Blackfin: add serial TX IRQ in individual platform resource
virtio-pci: fix use after free
ACPI / cpuidle: Remove acpi_idle_suspend (to fix suspend regression)
drm/radeon/kms/combios: fix dynamic allocation of PM clock modes
[CPUFREQ] db8500: fix build error due to undeclared i variable
bma023: Add SFI translation for this device
vrtc: change its year offset from 1960 to 1972
ce4100: fix a build error
arm/imx: fix imx6q mmc error when mounting rootfs
arm/imx: fix AUTO_ZRELADDR selection
arm/imx: fix the references to ARCH_MX3
ARM: mx51/53: set pwm clock parent to ipg_perclk
btrfs: rename the option to nospace_cache
drm/radeon/kms/pm: switch to dynamically allocating clock mode array
drm/radeon/kms: optimize r600_pm_profile_init
drm/radeon/kms/pm: add a proper pm profile init function for fusion
...
Conflicts:
drivers/media/radio/Kconfig
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index a88948b8bd17..a901c6901bce 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -225,7 +225,7 @@ static void dentry_unlink_inode(struct dentry * dentry) } /* - * dentry_lru_(add|del|move_tail) must be called with d_lock held. + * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held. */ static void dentry_lru_add(struct dentry *dentry) { @@ -245,6 +245,9 @@ static void __dentry_lru_del(struct dentry *dentry) dentry_stat.nr_unused--; } +/* + * Remove a dentry with references from the LRU. + */ static void dentry_lru_del(struct dentry *dentry) { if (!list_empty(&dentry->d_lru)) { @@ -254,6 +257,23 @@ static void dentry_lru_del(struct dentry *dentry) } } +/* + * Remove a dentry that is unreferenced and about to be pruned + * (unhashed and destroyed) from the LRU, and inform the file system. + * This wrapper should be called _prior_ to unhashing a victim dentry. + */ +static void dentry_lru_prune(struct dentry *dentry) +{ + if (!list_empty(&dentry->d_lru)) { + if (dentry->d_flags & DCACHE_OP_PRUNE) + dentry->d_op->d_prune(dentry); + + spin_lock(&dcache_lru_lock); + __dentry_lru_del(dentry); + spin_unlock(&dcache_lru_lock); + } +} + static void dentry_lru_move_tail(struct dentry *dentry) { spin_lock(&dcache_lru_lock); @@ -403,8 +423,12 @@ relock: if (ref) dentry->d_count--; - /* if dentry was on the d_lru list delete it from there */ - dentry_lru_del(dentry); + /* + * if dentry was on the d_lru list delete it from there. + * inform the fs via d_prune that this dentry is about to be + * unhashed and destroyed. + */ + dentry_lru_prune(dentry); /* if it was on the hash then remove it */ __d_drop(dentry); return d_kill(dentry, parent); @@ -522,9 +546,11 @@ int d_invalidate(struct dentry * dentry) * would make it unreachable from the root, * we might still populate it if it was a * working directory or similar). + * We also need to leave mountpoints alone, + * directory or not. */ - if (dentry->d_count > 1) { - if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { + if (dentry->d_count > 1 && dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) { spin_unlock(&dentry->d_lock); return -EBUSY; } @@ -854,8 +880,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) do { struct inode *inode; - /* detach from the system */ - dentry_lru_del(dentry); + /* + * remove the dentry from the lru, and inform + * the fs that this dentry is about to be + * unhashed and destroyed. + */ + dentry_lru_prune(dentry); __d_shrink(dentry); if (dentry->d_count != 0) { @@ -1283,6 +1313,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) dentry->d_flags |= DCACHE_OP_REVALIDATE; if (op->d_delete) dentry->d_flags |= DCACHE_OP_DELETE; + if (op->d_prune) + dentry->d_flags |= DCACHE_OP_PRUNE; } EXPORT_SYMBOL(d_set_d_op); |