mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-27 03:03:18 -04:00
Merge tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull dcache updates from Al Viro:
"Change of locking rules for __dentry_kill(), regularized refcounting
rules in that area, assorted cleanups and removal of weird corner
cases (e.g. now ->d_iput() on child is always called before the parent
might hit __dentry_kill(), etc)"
* tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits)
dcache: remove unnecessary NULL check in dget_dlock()
kill DCACHE_MAY_FREE
__d_unalias() doesn't use inode argument
d_alloc_parallel(): in-lookup hash insertion doesn't need an RCU variant
get rid of DCACHE_GENOCIDE
d_genocide(): move the extern into fs/internal.h
simple_fill_super(): don't bother with d_genocide() on failure
nsfs: use d_make_root()
d_alloc_pseudo(): move setting ->d_op there from the (sole) caller
kill d_instantate_anon(), fold __d_instantiate_anon() into remaining caller
retain_dentry(): introduce a trimmed-down lockless variant
__dentry_kill(): new locking scheme
d_prune_aliases(): use a shrink list
switch select_collect{,2}() to use of to_shrink_list()
to_shrink_list(): call only if refcount is 0
fold dentry_kill() into dput()
don't try to cut corners in shrink_lock_dentry()
fold the call of retain_dentry() into fast_dput()
Call retain_dentry() with refcount 0
dentry_kill(): don't bother with retain_dentry() on slow path
...
This commit is contained in:
@@ -68,12 +68,12 @@ extern const struct qstr dotdot_name;
|
||||
* large memory footprint increase).
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
# define DNAME_INLINE_LEN 32 /* 192 bytes */
|
||||
# define DNAME_INLINE_LEN 40 /* 192 bytes */
|
||||
#else
|
||||
# ifdef CONFIG_SMP
|
||||
# define DNAME_INLINE_LEN 36 /* 128 bytes */
|
||||
# else
|
||||
# define DNAME_INLINE_LEN 40 /* 128 bytes */
|
||||
# else
|
||||
# define DNAME_INLINE_LEN 44 /* 128 bytes */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -101,8 +101,8 @@ struct dentry {
|
||||
struct list_head d_lru; /* LRU list */
|
||||
wait_queue_head_t *d_wait; /* in-lookup ones only */
|
||||
};
|
||||
struct list_head d_child; /* child of parent list */
|
||||
struct list_head d_subdirs; /* our children */
|
||||
struct hlist_node d_sib; /* child of parent list */
|
||||
struct hlist_head d_children; /* our children */
|
||||
/*
|
||||
* d_alias and d_rcu can share memory
|
||||
*/
|
||||
@@ -111,7 +111,7 @@ struct dentry {
|
||||
struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */
|
||||
struct rcu_head d_rcu;
|
||||
} d_u;
|
||||
} __randomize_layout;
|
||||
};
|
||||
|
||||
/*
|
||||
* dentry->d_lock spinlock nesting subclasses:
|
||||
@@ -151,13 +151,13 @@ struct dentry_operations {
|
||||
*/
|
||||
|
||||
/* d_flags entries */
|
||||
#define DCACHE_OP_HASH 0x00000001
|
||||
#define DCACHE_OP_COMPARE 0x00000002
|
||||
#define DCACHE_OP_REVALIDATE 0x00000004
|
||||
#define DCACHE_OP_DELETE 0x00000008
|
||||
#define DCACHE_OP_PRUNE 0x00000010
|
||||
#define DCACHE_OP_HASH BIT(0)
|
||||
#define DCACHE_OP_COMPARE BIT(1)
|
||||
#define DCACHE_OP_REVALIDATE BIT(2)
|
||||
#define DCACHE_OP_DELETE BIT(3)
|
||||
#define DCACHE_OP_PRUNE BIT(4)
|
||||
|
||||
#define DCACHE_DISCONNECTED 0x00000020
|
||||
#define DCACHE_DISCONNECTED BIT(5)
|
||||
/* This dentry is possibly not currently connected to the dcache tree, in
|
||||
* which case its parent will either be itself, or will have this flag as
|
||||
* well. nfsd will not use a dentry with this bit set, but will first
|
||||
@@ -168,50 +168,46 @@ struct dentry_operations {
|
||||
* dentry into place and return that dentry rather than the passed one,
|
||||
* typically using d_splice_alias. */
|
||||
|
||||
#define DCACHE_REFERENCED 0x00000040 /* Recently used, don't discard. */
|
||||
#define DCACHE_REFERENCED BIT(6) /* Recently used, don't discard. */
|
||||
|
||||
#define DCACHE_DONTCACHE 0x00000080 /* Purge from memory on final dput() */
|
||||
#define DCACHE_DONTCACHE BIT(7) /* Purge from memory on final dput() */
|
||||
|
||||
#define DCACHE_CANT_MOUNT 0x00000100
|
||||
#define DCACHE_GENOCIDE 0x00000200
|
||||
#define DCACHE_SHRINK_LIST 0x00000400
|
||||
#define DCACHE_CANT_MOUNT BIT(8)
|
||||
#define DCACHE_SHRINK_LIST BIT(10)
|
||||
|
||||
#define DCACHE_OP_WEAK_REVALIDATE 0x00000800
|
||||
#define DCACHE_OP_WEAK_REVALIDATE BIT(11)
|
||||
|
||||
#define DCACHE_NFSFS_RENAMED 0x00001000
|
||||
#define DCACHE_NFSFS_RENAMED BIT(12)
|
||||
/* this dentry has been "silly renamed" and has to be deleted on the last
|
||||
* dput() */
|
||||
#define DCACHE_COOKIE 0x00002000 /* For use by dcookie subsystem */
|
||||
#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x00004000
|
||||
#define DCACHE_FSNOTIFY_PARENT_WATCHED BIT(14)
|
||||
/* Parent inode is watched by some fsnotify listener */
|
||||
|
||||
#define DCACHE_DENTRY_KILLED 0x00008000
|
||||
#define DCACHE_DENTRY_KILLED BIT(15)
|
||||
|
||||
#define DCACHE_MOUNTED 0x00010000 /* is a mountpoint */
|
||||
#define DCACHE_NEED_AUTOMOUNT 0x00020000 /* handle automount on this dir */
|
||||
#define DCACHE_MANAGE_TRANSIT 0x00040000 /* manage transit from this dirent */
|
||||
#define DCACHE_MOUNTED BIT(16) /* is a mountpoint */
|
||||
#define DCACHE_NEED_AUTOMOUNT BIT(17) /* handle automount on this dir */
|
||||
#define DCACHE_MANAGE_TRANSIT BIT(18) /* manage transit from this dirent */
|
||||
#define DCACHE_MANAGED_DENTRY \
|
||||
(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
|
||||
|
||||
#define DCACHE_LRU_LIST 0x00080000
|
||||
#define DCACHE_LRU_LIST BIT(19)
|
||||
|
||||
#define DCACHE_ENTRY_TYPE 0x00700000
|
||||
#define DCACHE_MISS_TYPE 0x00000000 /* Negative dentry (maybe fallthru to nowhere) */
|
||||
#define DCACHE_WHITEOUT_TYPE 0x00100000 /* Whiteout dentry (stop pathwalk) */
|
||||
#define DCACHE_DIRECTORY_TYPE 0x00200000 /* Normal directory */
|
||||
#define DCACHE_AUTODIR_TYPE 0x00300000 /* Lookupless directory (presumed automount) */
|
||||
#define DCACHE_REGULAR_TYPE 0x00400000 /* Regular file type (or fallthru to such) */
|
||||
#define DCACHE_SPECIAL_TYPE 0x00500000 /* Other file type (or fallthru to such) */
|
||||
#define DCACHE_SYMLINK_TYPE 0x00600000 /* Symlink (or fallthru to such) */
|
||||
#define DCACHE_ENTRY_TYPE (7 << 20) /* bits 20..22 are for storing type: */
|
||||
#define DCACHE_MISS_TYPE (0 << 20) /* Negative dentry */
|
||||
#define DCACHE_WHITEOUT_TYPE (1 << 20) /* Whiteout dentry (stop pathwalk) */
|
||||
#define DCACHE_DIRECTORY_TYPE (2 << 20) /* Normal directory */
|
||||
#define DCACHE_AUTODIR_TYPE (3 << 20) /* Lookupless directory (presumed automount) */
|
||||
#define DCACHE_REGULAR_TYPE (4 << 20) /* Regular file type */
|
||||
#define DCACHE_SPECIAL_TYPE (5 << 20) /* Other file type */
|
||||
#define DCACHE_SYMLINK_TYPE (6 << 20) /* Symlink */
|
||||
|
||||
#define DCACHE_MAY_FREE 0x00800000
|
||||
#define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */
|
||||
#define DCACHE_NOKEY_NAME 0x02000000 /* Encrypted name encoded without key */
|
||||
#define DCACHE_OP_REAL 0x04000000
|
||||
#define DCACHE_NOKEY_NAME BIT(25) /* Encrypted name encoded without key */
|
||||
#define DCACHE_OP_REAL BIT(26)
|
||||
|
||||
#define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */
|
||||
#define DCACHE_DENTRY_CURSOR 0x20000000
|
||||
#define DCACHE_NORCU 0x40000000 /* No RCU delay for freeing */
|
||||
#define DCACHE_PAR_LOOKUP BIT(28) /* being looked up (with parent locked shared) */
|
||||
#define DCACHE_DENTRY_CURSOR BIT(29)
|
||||
#define DCACHE_NORCU BIT(30) /* No RCU delay for freeing */
|
||||
|
||||
extern seqlock_t rename_lock;
|
||||
|
||||
@@ -220,8 +216,6 @@ extern seqlock_t rename_lock;
|
||||
*/
|
||||
extern void d_instantiate(struct dentry *, struct inode *);
|
||||
extern void d_instantiate_new(struct dentry *, struct inode *);
|
||||
extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
|
||||
extern struct dentry * d_instantiate_anon(struct dentry *, struct inode *);
|
||||
extern void __d_drop(struct dentry *dentry);
|
||||
extern void d_drop(struct dentry *dentry);
|
||||
extern void d_delete(struct dentry *);
|
||||
@@ -242,15 +236,11 @@ extern struct dentry * d_obtain_alias(struct inode *);
|
||||
extern struct dentry * d_obtain_root(struct inode *);
|
||||
extern void shrink_dcache_sb(struct super_block *);
|
||||
extern void shrink_dcache_parent(struct dentry *);
|
||||
extern void shrink_dcache_for_umount(struct super_block *);
|
||||
extern void d_invalidate(struct dentry *);
|
||||
|
||||
/* only used at mount-time */
|
||||
extern struct dentry * d_make_root(struct inode *);
|
||||
|
||||
/* <clickety>-<click> the ramfs-type tree */
|
||||
extern void d_genocide(struct dentry *);
|
||||
|
||||
extern void d_mark_tmpfile(struct file *, struct inode *);
|
||||
extern void d_tmpfile(struct file *, struct inode *);
|
||||
|
||||
@@ -274,12 +264,8 @@ extern void d_move(struct dentry *, struct dentry *);
|
||||
extern void d_exchange(struct dentry *, struct dentry *);
|
||||
extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
|
||||
|
||||
/* appendix may either be NULL or be used for transname suffixes */
|
||||
extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
|
||||
extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
|
||||
extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
|
||||
extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
|
||||
const struct qstr *name, unsigned *seq);
|
||||
|
||||
static inline unsigned d_count(const struct dentry *dentry)
|
||||
{
|
||||
@@ -301,20 +287,40 @@ extern char *dentry_path(const struct dentry *, char *, int);
|
||||
/* Allocation counts.. */
|
||||
|
||||
/**
|
||||
* dget, dget_dlock - get a reference to a dentry
|
||||
* @dentry: dentry to get a reference to
|
||||
* dget_dlock - get a reference to a dentry
|
||||
* @dentry: dentry to get a reference to
|
||||
*
|
||||
* Given a dentry or %NULL pointer increment the reference count
|
||||
* if appropriate and return the dentry. A dentry will not be
|
||||
* destroyed when it has references.
|
||||
* Given a live dentry, increment the reference count and return the dentry.
|
||||
* Caller must hold @dentry->d_lock. Making sure that dentry is alive is
|
||||
* caller's resonsibility. There are many conditions sufficient to guarantee
|
||||
* that; e.g. anything with non-negative refcount is alive, so's anything
|
||||
* hashed, anything positive, anyone's parent, etc.
|
||||
*/
|
||||
static inline struct dentry *dget_dlock(struct dentry *dentry)
|
||||
{
|
||||
if (dentry)
|
||||
dentry->d_lockref.count++;
|
||||
dentry->d_lockref.count++;
|
||||
return dentry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dget - get a reference to a dentry
|
||||
* @dentry: dentry to get a reference to
|
||||
*
|
||||
* Given a dentry or %NULL pointer increment the reference count
|
||||
* if appropriate and return the dentry. A dentry will not be
|
||||
* destroyed when it has references. Conversely, a dentry with
|
||||
* no references can disappear for any number of reasons, starting
|
||||
* with memory pressure. In other words, that primitive is
|
||||
* used to clone an existing reference; using it on something with
|
||||
* zero refcount is a bug.
|
||||
*
|
||||
* NOTE: it will spin if @dentry->d_lock is held. From the deadlock
|
||||
* avoidance point of view it is equivalent to spin_lock()/increment
|
||||
* refcount/spin_unlock(), so calling it under @dentry->d_lock is
|
||||
* always a bug; so's calling it under ->d_lock on any of its descendents.
|
||||
*
|
||||
*/
|
||||
static inline struct dentry *dget(struct dentry *dentry)
|
||||
{
|
||||
if (dentry)
|
||||
@@ -325,12 +331,11 @@ static inline struct dentry *dget(struct dentry *dentry)
|
||||
extern struct dentry *dget_parent(struct dentry *dentry);
|
||||
|
||||
/**
|
||||
* d_unhashed - is dentry hashed
|
||||
* @dentry: entry to check
|
||||
* d_unhashed - is dentry hashed
|
||||
* @dentry: entry to check
|
||||
*
|
||||
* Returns true if the dentry passed is not currently hashed.
|
||||
* Returns true if the dentry passed is not currently hashed.
|
||||
*/
|
||||
|
||||
static inline int d_unhashed(const struct dentry *dentry)
|
||||
{
|
||||
return hlist_bl_unhashed(&dentry->d_hash);
|
||||
@@ -490,14 +495,6 @@ static inline int simple_positive(const struct dentry *dentry)
|
||||
return d_really_is_positive(dentry) && !d_unhashed(dentry);
|
||||
}
|
||||
|
||||
extern void d_set_fallthru(struct dentry *dentry);
|
||||
|
||||
static inline bool d_is_fallthru(const struct dentry *dentry)
|
||||
{
|
||||
return dentry->d_flags & DCACHE_FALLTHRU;
|
||||
}
|
||||
|
||||
|
||||
extern int sysctl_vfs_cache_pressure;
|
||||
|
||||
static inline unsigned long vfs_pressure_ratio(unsigned long val)
|
||||
@@ -546,21 +543,6 @@ static inline struct inode *d_backing_inode(const struct dentry *upper)
|
||||
return inode;
|
||||
}
|
||||
|
||||
/**
|
||||
* d_backing_dentry - Get upper or lower dentry we should be using
|
||||
* @upper: The upper layer
|
||||
*
|
||||
* This is the helper that should be used to get the dentry of the inode that
|
||||
* will be used if this dentry were opened as a file. It may be the upper
|
||||
* dentry or it may be a lower dentry pinned by the upper.
|
||||
*
|
||||
* Normal filesystems should not use this to access their own dentries.
|
||||
*/
|
||||
static inline struct dentry *d_backing_dentry(struct dentry *upper)
|
||||
{
|
||||
return upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* d_real - Return the real dentry
|
||||
* @dentry: the dentry to query
|
||||
@@ -600,4 +582,14 @@ struct name_snapshot {
|
||||
void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
|
||||
void release_dentry_name_snapshot(struct name_snapshot *);
|
||||
|
||||
static inline struct dentry *d_first_child(const struct dentry *dentry)
|
||||
{
|
||||
return hlist_entry_safe(dentry->d_children.first, struct dentry, d_sib);
|
||||
}
|
||||
|
||||
static inline struct dentry *d_next_sibling(const struct dentry *dentry)
|
||||
{
|
||||
return hlist_entry_safe(dentry->d_sib.next, struct dentry, d_sib);
|
||||
}
|
||||
|
||||
#endif /* __LINUX_DCACHE_H */
|
||||
|
||||
Reference in New Issue
Block a user