fs: change d_delete semantics

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 <npiggin@kernel.dk>
This commit is contained in:
Nick Piggin 2011-01-07 17:49:23 +11:00
parent 5eef7fa905
commit fe15ce446b
22 changed files with 47 additions and 42 deletions

View File

@ -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).

View File

@ -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);
@ -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
@ -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

View File

@ -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;
}

View File

@ -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 =
{
@ -367,7 +367,7 @@ out:
* 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)) {

View File

@ -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);
@ -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,

View File

@ -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);
@ -730,7 +730,7 @@ out_bad:
* - 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);

View File

@ -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;

View File

@ -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,
@ -577,7 +577,7 @@ out:
* 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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 =
{
@ -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;

View File

@ -1117,7 +1117,7 @@ out_error:
/*
* 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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}