Skip to content

Commit 7fe1b48

Browse files
Al ViroKernel Patches Daemon
authored andcommitted
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 <[email protected]>
1 parent da0e437 commit 7fe1b48

File tree

6 files changed

+39
-19
lines changed

6 files changed

+39
-19
lines changed

fs/configfs/dir.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,14 @@ static void remove_dir(struct dentry * d)
400400

401401
configfs_remove_dirent(d);
402402

403-
if (d_really_is_positive(d))
404-
simple_rmdir(d_inode(parent),d);
403+
if (d_really_is_positive(d)) {
404+
if (likely(simple_empty(d))) {
405+
__simple_rmdir(d_inode(parent),d);
406+
dput(d);
407+
} else {
408+
pr_warn("remove_dir (%pd): attributes remain", d);
409+
}
410+
}
405411

406412
pr_debug(" o %pd removing done (%d)\n", d, d_count(d));
407413

fs/configfs/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,8 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
211211
dget_dlock(dentry);
212212
__d_drop(dentry);
213213
spin_unlock(&dentry->d_lock);
214-
simple_unlink(d_inode(parent), dentry);
214+
__simple_unlink(d_inode(parent), dentry);
215+
dput(dentry);
215216
} else
216217
spin_unlock(&dentry->d_lock);
217218
}

fs/dcache.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -931,14 +931,7 @@ EXPORT_SYMBOL(dput);
931931
void d_make_discardable(struct dentry *dentry)
932932
{
933933
spin_lock(&dentry->d_lock);
934-
/*
935-
* By the end of the series we'll add
936-
* WARN_ON(!(dentry->d_flags & DCACHE_PERSISTENT);
937-
* here, but while object removal is done by a few common helpers,
938-
* object creation tends to be open-coded (if nothing else, new inode
939-
* needs to be set up), so adding a warning from the very beginning
940-
* would make for much messier patch series.
941-
*/
934+
WARN_ON(!(dentry->d_flags & DCACHE_PERSISTENT));
942935
dentry->d_flags &= ~DCACHE_PERSISTENT;
943936
dentry->d_lockref.count--;
944937
rcu_read_lock();

fs/libfs.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -790,13 +790,27 @@ int simple_empty(struct dentry *dentry)
790790
}
791791
EXPORT_SYMBOL(simple_empty);
792792

793-
int simple_unlink(struct inode *dir, struct dentry *dentry)
793+
void __simple_unlink(struct inode *dir, struct dentry *dentry)
794794
{
795795
struct inode *inode = d_inode(dentry);
796796

797797
inode_set_mtime_to_ts(dir,
798798
inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
799799
drop_nlink(inode);
800+
}
801+
EXPORT_SYMBOL(__simple_unlink);
802+
803+
void __simple_rmdir(struct inode *dir, struct dentry *dentry)
804+
{
805+
drop_nlink(d_inode(dentry));
806+
__simple_unlink(dir, dentry);
807+
drop_nlink(dir);
808+
}
809+
EXPORT_SYMBOL(__simple_rmdir);
810+
811+
int simple_unlink(struct inode *dir, struct dentry *dentry)
812+
{
813+
__simple_unlink(dir, dentry);
800814
d_make_discardable(dentry);
801815
return 0;
802816
}
@@ -807,9 +821,8 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
807821
if (!simple_empty(dentry))
808822
return -ENOTEMPTY;
809823

810-
drop_nlink(d_inode(dentry));
811-
simple_unlink(dir, dentry);
812-
drop_nlink(dir);
824+
__simple_rmdir(dir, dentry);
825+
d_make_discardable(dentry);
813826
return 0;
814827
}
815828
EXPORT_SYMBOL(simple_rmdir);

include/linux/fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3621,6 +3621,8 @@ extern int simple_open(struct inode *inode, struct file *file);
36213621
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
36223622
extern int simple_unlink(struct inode *, struct dentry *);
36233623
extern int simple_rmdir(struct inode *, struct dentry *);
3624+
extern void __simple_unlink(struct inode *, struct dentry *);
3625+
extern void __simple_rmdir(struct inode *, struct dentry *);
36243626
void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry,
36253627
struct inode *new_dir, struct dentry *new_dentry);
36263628
extern int simple_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,

security/apparmor/apparmorfs.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,15 @@ static void aafs_remove(struct dentry *dentry)
358358
dir = d_inode(dentry->d_parent);
359359
inode_lock(dir);
360360
if (simple_positive(dentry)) {
361-
if (d_is_dir(dentry))
362-
simple_rmdir(dir, dentry);
363-
else
364-
simple_unlink(dir, dentry);
361+
if (d_is_dir(dentry)) {
362+
if (!WARN_ON(!simple_empty(dentry))) {
363+
__simple_rmdir(dir, dentry);
364+
dput(dentry);
365+
}
366+
} else {
367+
__simple_unlink(dir, dentry);
368+
dput(dentry);
369+
}
365370
d_delete(dentry);
366371
dput(dentry);
367372
}

0 commit comments

Comments
 (0)