mirror of https://github.com/torvalds/linux.git
d_make_discardable(): warn if given a non-persistent dentry
At this point there are very few call chains that might lead to d_make_discardable() on a dentry that hadn't been made persistent: calls of simple_unlink() and simple_rmdir() in configfs and apparmorfs. Both filesystems do pin (part of) their contents in dcache, but they are currently playing very unusual games with that. Converting them to more usual patterns might be possible, but it's definitely going to be a long series of changes in both cases. For now the easiest solution is to have both stop using simple_unlink() and simple_rmdir() - that allows to make d_make_discardable() warn when given a non-persistent dentry. Rather than giving them full-blown private copies (with calls of d_make_discardable() replaced with dput()), let's pull the parts of simple_unlink() and simple_rmdir() that deal with timestamps and link counts into separate helpers (__simple_unlink() and __simple_rmdir() resp.) and have those used by configfs and apparmorfs. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
ca459ca70f
commit
eb028c3345
|
|
@ -400,8 +400,14 @@ static void remove_dir(struct dentry * d)
|
||||||
|
|
||||||
configfs_remove_dirent(d);
|
configfs_remove_dirent(d);
|
||||||
|
|
||||||
if (d_really_is_positive(d))
|
if (d_really_is_positive(d)) {
|
||||||
simple_rmdir(d_inode(parent),d);
|
if (likely(simple_empty(d))) {
|
||||||
|
__simple_rmdir(d_inode(parent),d);
|
||||||
|
dput(d);
|
||||||
|
} else {
|
||||||
|
pr_warn("remove_dir (%pd): attributes remain", d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pr_debug(" o %pd removing done (%d)\n", d, d_count(d));
|
pr_debug(" o %pd removing done (%d)\n", d, d_count(d));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,8 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
|
||||||
dget_dlock(dentry);
|
dget_dlock(dentry);
|
||||||
__d_drop(dentry);
|
__d_drop(dentry);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
simple_unlink(d_inode(parent), dentry);
|
__simple_unlink(d_inode(parent), dentry);
|
||||||
|
dput(dentry);
|
||||||
} else
|
} else
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -931,14 +931,7 @@ EXPORT_SYMBOL(dput);
|
||||||
void d_make_discardable(struct dentry *dentry)
|
void d_make_discardable(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
spin_lock(&dentry->d_lock);
|
spin_lock(&dentry->d_lock);
|
||||||
/*
|
WARN_ON(!(dentry->d_flags & DCACHE_PERSISTENT));
|
||||||
* By the end of the series we'll add
|
|
||||||
* WARN_ON(!(dentry->d_flags & DCACHE_PERSISTENT);
|
|
||||||
* here, but while object removal is done by a few common helpers,
|
|
||||||
* object creation tends to be open-coded (if nothing else, new inode
|
|
||||||
* needs to be set up), so adding a warning from the very beginning
|
|
||||||
* would make for much messier patch series.
|
|
||||||
*/
|
|
||||||
dentry->d_flags &= ~DCACHE_PERSISTENT;
|
dentry->d_flags &= ~DCACHE_PERSISTENT;
|
||||||
dentry->d_lockref.count--;
|
dentry->d_lockref.count--;
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
|
||||||
21
fs/libfs.c
21
fs/libfs.c
|
|
@ -790,13 +790,27 @@ int simple_empty(struct dentry *dentry)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(simple_empty);
|
EXPORT_SYMBOL(simple_empty);
|
||||||
|
|
||||||
int simple_unlink(struct inode *dir, struct dentry *dentry)
|
void __simple_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
|
|
||||||
inode_set_mtime_to_ts(dir,
|
inode_set_mtime_to_ts(dir,
|
||||||
inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
|
inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
|
||||||
drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__simple_unlink);
|
||||||
|
|
||||||
|
void __simple_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
drop_nlink(d_inode(dentry));
|
||||||
|
__simple_unlink(dir, dentry);
|
||||||
|
drop_nlink(dir);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__simple_rmdir);
|
||||||
|
|
||||||
|
int simple_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
__simple_unlink(dir, dentry);
|
||||||
d_make_discardable(dentry);
|
d_make_discardable(dentry);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -807,9 +821,8 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
if (!simple_empty(dentry))
|
if (!simple_empty(dentry))
|
||||||
return -ENOTEMPTY;
|
return -ENOTEMPTY;
|
||||||
|
|
||||||
drop_nlink(d_inode(dentry));
|
__simple_rmdir(dir, dentry);
|
||||||
simple_unlink(dir, dentry);
|
d_make_discardable(dentry);
|
||||||
drop_nlink(dir);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(simple_rmdir);
|
EXPORT_SYMBOL(simple_rmdir);
|
||||||
|
|
|
||||||
|
|
@ -3621,6 +3621,8 @@ extern int simple_open(struct inode *inode, struct file *file);
|
||||||
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
|
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
|
||||||
extern int simple_unlink(struct inode *, struct dentry *);
|
extern int simple_unlink(struct inode *, struct dentry *);
|
||||||
extern int simple_rmdir(struct inode *, struct dentry *);
|
extern int simple_rmdir(struct inode *, struct dentry *);
|
||||||
|
extern void __simple_unlink(struct inode *, struct dentry *);
|
||||||
|
extern void __simple_rmdir(struct inode *, struct dentry *);
|
||||||
void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry,
|
void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
struct inode *new_dir, struct dentry *new_dentry);
|
struct inode *new_dir, struct dentry *new_dentry);
|
||||||
extern int simple_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,
|
extern int simple_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
|
|
|
||||||
|
|
@ -358,10 +358,15 @@ static void aafs_remove(struct dentry *dentry)
|
||||||
dir = d_inode(dentry->d_parent);
|
dir = d_inode(dentry->d_parent);
|
||||||
inode_lock(dir);
|
inode_lock(dir);
|
||||||
if (simple_positive(dentry)) {
|
if (simple_positive(dentry)) {
|
||||||
if (d_is_dir(dentry))
|
if (d_is_dir(dentry)) {
|
||||||
simple_rmdir(dir, dentry);
|
if (!WARN_ON(!simple_empty(dentry))) {
|
||||||
else
|
__simple_rmdir(dir, dentry);
|
||||||
simple_unlink(dir, dentry);
|
dput(dentry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__simple_unlink(dir, dentry);
|
||||||
|
dput(dentry);
|
||||||
|
}
|
||||||
d_delete(dentry);
|
d_delete(dentry);
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue