Skip to content

Commit

Permalink
fs: change d_delete semantics
Browse files Browse the repository at this point in the history
Change d_delete from a dentry deletion notification to a dentry caching
advise, more like ->drop_inode. Require it to be constant and idempotent,
and not take d_lock. This is how all existing filesystems use the callback
anyway.

This makes fine grained dentry locking of dput and dentry lru scanning
much simpler.

Signed-off-by: Nick Piggin <[email protected]>
  • Loading branch information
Nick Piggin committed Jan 7, 2011
1 parent 5eef7fa commit fe15ce4
Show file tree
Hide file tree
Showing 22 changed files with 47 additions and 42 deletions.
8 changes: 8 additions & 0 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,11 @@ if it's zero is not *and* *never* *had* *been* enough. Final unlink() and iput(
may happen while the inode is in the middle of ->write_inode(); e.g. if you blindly
free the on-disk inode, you may end up doing that while ->write_inode() is writing
to it.

---
[mandatory]

.d_delete() now only advises the dcache as to whether or not to cache
unreferenced dentries, and is now only called when the dentry refcount goes to
0. Even on 0 refcount transition, it must be able to tolerate being called 0,
1, or more times (eg. constant, idempotent).
27 changes: 13 additions & 14 deletions Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -847,9 +847,9 @@ defined:

struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash) (struct dentry *, struct qstr *);
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
int (*d_delete)(struct dentry *);
int (*d_hash)(struct dentry *, struct qstr *);
int (*d_compare)(struct dentry *, struct qstr *, struct qstr *);
int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
Expand All @@ -864,9 +864,11 @@ struct dentry_operations {

d_compare: called when a dentry should be compared with another

d_delete: called when the last reference to a dentry is
deleted. This means no-one is using the dentry, however it is
still valid and in the dcache
d_delete: called when the last reference to a dentry is dropped and the
dcache is deciding whether or not to cache it. Return 1 to delete
immediately, or 0 to cache the dentry. Default is NULL which means to
always cache a reachable dentry. d_delete must be constant and
idempotent.

d_release: called when a dentry is really deallocated

Expand Down Expand Up @@ -910,14 +912,11 @@ manipulate dentries:
the usage count)

dput: close a handle for a dentry (decrements the usage count). If
the usage count drops to 0, the "d_delete" method is called
and the dentry is placed on the unused list if the dentry is
still in its parents hash list. Putting the dentry on the
unused list just means that if the system needs some RAM, it
goes through the unused list of dentries and deallocates them.
If the dentry has already been unhashed and the usage count
drops to 0, in this case the dentry is deallocated after the
"d_delete" method is called
the usage count drops to 0, and the dentry is still in its
parent's hash, the "d_delete" method is called to check whether
it should be cached. If it should not be cached, or if the dentry
is not hashed, it is deleted. Otherwise cached dentries are put
into an LRU list to be reclaimed on memory shortage.

d_drop: this unhashes a dentry from its parents hash list. A
subsequent call to dput() will deallocate the dentry if its
Expand Down
2 changes: 1 addition & 1 deletion arch/ia64/kernel/perfmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -2185,7 +2185,7 @@ static const struct file_operations pfm_file_ops = {
};

static int
pfmfs_delete_dentry(struct dentry *dentry)
pfmfs_delete_dentry(const struct dentry *dentry)
{
return 1;
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/staging/smbfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ smb_dir_open(struct inode *dir, struct file *file)
static int smb_lookup_validate(struct dentry *, struct nameidata *);
static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static int smb_delete_dentry(struct dentry *);
static int smb_delete_dentry(const struct dentry *);

static const struct dentry_operations smbfs_dentry_operations =
{
Expand Down Expand Up @@ -367,7 +367,7 @@ smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
* We use this to unhash dentries with bad inodes.
*/
static int
smb_delete_dentry(struct dentry * dentry)
smb_delete_dentry(const struct dentry *dentry)
{
if (dentry->d_inode) {
if (is_bad_inode(dentry->d_inode)) {
Expand Down
4 changes: 2 additions & 2 deletions fs/9p/vfs_dentry.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
*
*/

static int v9fs_dentry_delete(struct dentry *dentry)
static int v9fs_dentry_delete(const struct dentry *dentry)
{
P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
dentry);
Expand All @@ -68,7 +68,7 @@ static int v9fs_dentry_delete(struct dentry *dentry)
*
*/

static int v9fs_cached_dentry_delete(struct dentry *dentry)
static int v9fs_cached_dentry_delete(const struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
Expand Down
4 changes: 2 additions & 2 deletions fs/afs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
static int afs_dir_open(struct inode *inode, struct file *file);
static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
static int afs_d_delete(struct dentry *dentry);
static int afs_d_delete(const struct dentry *dentry);
static void afs_d_release(struct dentry *dentry);
static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
loff_t fpos, u64 ino, unsigned dtype);
Expand Down Expand Up @@ -730,7 +730,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
* - called from dput() when d_count is going to 0.
* - return 1 to request dentry be unhashed, 0 otherwise
*/
static int afs_d_delete(struct dentry *dentry)
static int afs_d_delete(const struct dentry *dentry)
{
_enter("%s", dentry->d_name.name);

Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -4127,7 +4127,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
return inode;
}

static int btrfs_dentry_delete(struct dentry *dentry)
static int btrfs_dentry_delete(const struct dentry *dentry)
{
struct btrfs_root *root;

Expand Down
4 changes: 2 additions & 2 deletions fs/coda/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static int coda_readdir(struct file *file, void *buf, filldir_t filldir);

/* dentry ops */
static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
static int coda_dentry_delete(struct dentry *);
static int coda_dentry_delete(const struct dentry *);

/* support routines */
static int coda_venus_readdir(struct file *coda_file, void *buf,
Expand Down Expand Up @@ -577,7 +577,7 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
* This is the callback from dput() when d_count is going to 0.
* We use this to unhash dentries with bad inodes.
*/
static int coda_dentry_delete(struct dentry * dentry)
static int coda_dentry_delete(const struct dentry * dentry)
{
int flags;

Expand Down
2 changes: 1 addition & 1 deletion fs/configfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ static void configfs_d_iput(struct dentry * dentry,
* We _must_ delete our dentries on last dput, as the chain-to-parent
* behavior is required to clear the parents of default_groups.
*/
static int configfs_d_delete(struct dentry *dentry)
static int configfs_d_delete(const struct dentry *dentry)
{
return 1;
}
Expand Down
2 changes: 0 additions & 2 deletions fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,6 @@ static void prune_one_dentry(struct dentry * dentry)
if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))
return;

if (dentry->d_op && dentry->d_op->d_delete)
dentry->d_op->d_delete(dentry);
dentry_lru_del(dentry);
__d_drop(dentry);
dentry = d_kill(dentry);
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/dentry.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
return 0;
}

static int gfs2_dentry_delete(struct dentry *dentry)
static int gfs2_dentry_delete(const struct dentry *dentry)
{
struct gfs2_inode *ginode;

Expand Down
2 changes: 1 addition & 1 deletion fs/hostfs/hostfs_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)

#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)

static int hostfs_d_delete(struct dentry *dentry)
static int hostfs_d_delete(const struct dentry *dentry)
{
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/libfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ int simple_statfs(struct dentry *dentry, struct kstatfs *buf)
* Retaining negative dentries for an in-memory filesystem just wastes
* memory and lookup time: arrange for them to be deleted immediately.
*/
static int simple_delete_dentry(struct dentry *dentry)
static int simple_delete_dentry(const struct dentry *dentry)
{
return 1;
}
Expand Down
4 changes: 2 additions & 2 deletions fs/ncpfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const struct inode_operations ncp_dir_inode_operations =
static int ncp_lookup_validate(struct dentry *, struct nameidata *);
static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
static int ncp_delete_dentry(struct dentry *);
static int ncp_delete_dentry(const struct dentry *);

static const struct dentry_operations ncp_dentry_operations =
{
Expand Down Expand Up @@ -162,7 +162,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
* Closing files can be safely postponed until iput() - it's done there anyway.
*/
static int
ncp_delete_dentry(struct dentry * dentry)
ncp_delete_dentry(const struct dentry * dentry)
{
struct inode *inode = dentry->d_inode;

Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
/*
* This is called from dput() when d_count is going to 0.
*/
static int nfs_dentry_delete(struct dentry *dentry)
static int nfs_dentry_delete(const struct dentry *dentry)
{
dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
Expand Down
2 changes: 1 addition & 1 deletion fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -1744,7 +1744,7 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
return 0;
}

static int pid_delete_dentry(struct dentry * dentry)
static int pid_delete_dentry(const struct dentry * dentry)
{
/* Is the task we represent dead?
* If so, then don't put the dentry on the lru list,
Expand Down
2 changes: 1 addition & 1 deletion fs/proc/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ static const struct inode_operations proc_link_inode_operations = {
* smarter: we could keep a "volatile" flag in the
* inode to indicate which ones to keep.
*/
static int proc_delete_dentry(struct dentry * dentry)
static int proc_delete_dentry(const struct dentry * dentry)
{
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/proc/proc_sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
return !PROC_I(dentry->d_inode)->sysctl->unregistering;
}

static int proc_sys_delete(struct dentry *dentry)
static int proc_sys_delete(const struct dentry *dentry)
{
return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/sysfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
goto repeat;
}

static int sysfs_dentry_delete(struct dentry *dentry)
static int sysfs_dentry_delete(const struct dentry *dentry)
{
struct sysfs_dirent *sd = dentry->d_fsdata;
return !!(sd->s_flags & SYSFS_FLAG_REMOVED);
Expand Down
6 changes: 3 additions & 3 deletions include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ enum dentry_d_lock_class

struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash) (struct dentry *, struct qstr *);
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
int (*d_delete)(struct dentry *);
int (*d_hash)(struct dentry *, struct qstr *);
int (*d_compare)(struct dentry *, struct qstr *, struct qstr *);
int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
Expand Down
2 changes: 1 addition & 1 deletion kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2198,7 +2198,7 @@ static inline struct cftype *__file_cft(struct file *file)
return __d_cft(file->f_dentry);
}

static int cgroup_delete_dentry(struct dentry *dentry)
static int cgroup_delete_dentry(const struct dentry *dentry)
{
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion net/sunrpc/rpc_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ void rpc_put_mount(void)
}
EXPORT_SYMBOL_GPL(rpc_put_mount);

static int rpc_delete_dentry(struct dentry *dentry)
static int rpc_delete_dentry(const struct dentry *dentry)
{
return 1;
}
Expand Down

0 comments on commit fe15ce4

Please sign in to comment.