#include <linux/spinlock.h>
#include <linux/cache.h>
#include <linux/rcupdate.h>
-#include <asm/bug.h>
struct nameidata;
struct vfsmount;
/*
* "quick string" -- eases parameter passing, but more importantly
* saves "metadata" about the string (ie length and the hash).
+ *
+ * hash comes first so it snuggles against d_parent in the
+ * dentry.
*/
struct qstr {
- const unsigned char * name;
- unsigned int len;
unsigned int hash;
- char name_str[0];
+ unsigned int len;
+ const unsigned char *name;
};
struct dentry_stat_t {
return end_name_hash(hash);
}
-#define DNAME_INLINE_LEN_MIN 24
-
struct dcookie_struct;
-
+
+#define DNAME_INLINE_LEN_MIN 36
+
struct dentry {
atomic_t d_count;
+ unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
- unsigned long d_vfs_flags; /* moved here to be on same cacheline */
- struct inode * d_inode; /* Where the name belongs to - NULL is negative */
+ struct inode *d_inode; /* Where the name belongs to - NULL is
+ * negative */
+ /*
+ * The next three fields are touched by __d_lookup. Place them here
+ * so they all fit in a cache line.
+ */
+ struct hlist_node d_hash; /* lookup hash list */
+ struct dentry *d_parent; /* parent directory */
+ struct qstr d_name;
+
struct list_head d_lru; /* LRU list */
- struct list_head d_child; /* child of parent list */
+ /*
+ * d_child and d_rcu can share memory
+ */
+ union {
+ struct list_head d_child; /* child of parent list */
+ struct rcu_head d_rcu;
+ } d_u;
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
- struct dentry_operations *d_op;
- struct super_block * d_sb; /* The root of the dentry tree */
- unsigned int d_flags;
+ struct dentry_operations *d_op;
+ struct super_block *d_sb; /* The root of the dentry tree */
+ void *d_fsdata; /* fs-specific data */
+ void *d_extra_attributes; /* TUX-specific data */
+#ifdef CONFIG_PROFILING
+ struct dcookie_struct *d_cookie; /* cookie, if any */
+#endif
int d_mounted;
- void * d_fsdata; /* fs-specific data */
- struct rcu_head d_rcu;
- struct dcookie_struct * d_cookie; /* cookie, if any */
- unsigned long d_move_count; /* to indicated moved dentry while lockless lookup */
- struct qstr * d_qstr; /* quick str ptr used in lockless lookup and concurrent d_move */
- struct dentry * d_parent; /* parent directory */
- struct qstr d_name;
- struct hlist_node d_hash; /* lookup hash list */
- struct hlist_head * d_bucket; /* lookup hash bucket */
- unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
+ unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
-#define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname))
-
struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash) (struct dentry *, struct qstr *);
/*
locking rules:
- big lock dcache_lock may block
-d_revalidate: no no yes
-d_hash no no yes
-d_compare: no yes no
-d_delete: no yes no
-d_release: no no yes
-d_iput: no no yes
+ big lock dcache_lock d_lock may block
+d_revalidate: no no no yes
+d_hash no no no yes
+d_compare: no yes yes no
+d_delete: no yes no no
+d_release: no no no yes
+d_iput: no no no yes
*/
/* d_flags entries */
#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
#define DCACHE_UNHASHED 0x0010
+#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */
+
extern spinlock_t dcache_lock;
/**
* d_drop - drop a dentry
* @dentry: dentry to drop
*
- * d_drop() unhashes the entry from the parent
- * dentry hashes, so that it won't be found through
- * a VFS lookup any more. Note that this is different
- * from deleting the dentry - d_delete will try to
- * mark the dentry negative if possible, giving a
- * successful _negative_ lookup, while d_drop will
+ * d_drop() unhashes the entry from the parent dentry hashes, so that it won't
+ * be found through a VFS lookup any more. Note that this is different from
+ * deleting the dentry - d_delete will try to mark the dentry negative if
+ * possible, giving a successful _negative_ lookup, while d_drop will
* just make the cache lookup fail.
*
- * d_drop() is used mainly for stuff that wants
- * to invalidate a dentry for some reason (NFS
- * timeouts or autofs deletes).
+ * d_drop() is used mainly for stuff that wants to invalidate a dentry for some
+ * reason (NFS timeouts or autofs deletes).
+ *
+ * __d_drop requires dentry->d_lock.
*/
static inline void __d_drop(struct dentry *dentry)
{
- if (!(dentry->d_vfs_flags & DCACHE_UNHASHED)) {
- dentry->d_vfs_flags |= DCACHE_UNHASHED;
+ if (!(dentry->d_flags & DCACHE_UNHASHED)) {
+ dentry->d_flags |= DCACHE_UNHASHED;
hlist_del_rcu(&dentry->d_hash);
}
}
static inline void d_drop(struct dentry *dentry)
{
spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
__d_drop(dentry);
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
}
-static inline int dname_external(struct dentry *d)
+static inline int dname_external(struct dentry *dentry)
{
- return d->d_name.name != d->d_iname;
+ return dentry->d_name.name != dentry->d_iname;
}
/*
* These are the low-level FS interfaces to the dcache..
*/
extern void d_instantiate(struct dentry *, struct inode *);
+extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
extern void d_delete(struct dentry *);
/* allocate/de-allocate */
extern void shrink_dcache_parent(struct dentry *);
extern void shrink_dcache_anon(struct hlist_head *);
extern int d_invalidate(struct dentry *);
+extern void flush_dentry_attributes(void);
/* only used at mount-time */
extern struct dentry * d_alloc_root(struct inode *);
d_rehash(entry);
}
+/**
+ * d_add_unique - add dentry to hash queues without aliasing
+ * @entry: dentry to add
+ * @inode: The inode to attach to this dentry
+ *
+ * This adds the entry to the hash queues and initializes @inode.
+ * The entry was actually filled in earlier during d_alloc().
+ */
+static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *inode)
+{
+ struct dentry *res;
+
+ res = d_instantiate_unique(entry, inode);
+ d_rehash(res != NULL ? res : entry);
+ return res;
+}
+
/* used for rename() and baskets */
extern void d_move(struct dentry *, struct dentry *);
/* appendix may either be NULL or be used for transname suffixes */
extern struct dentry * d_lookup(struct dentry *, struct qstr *);
extern struct dentry * __d_lookup(struct dentry *, struct qstr *);
+extern struct dentry * d_hash_and_lookup(struct dentry *, struct qstr *);
/* validate "insecure" dentry pointer */
extern int d_validate(struct dentry *, struct dentry *);
+char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
+ struct dentry *root, struct vfsmount *rootmnt,
+ char *buffer, int buflen);
+
extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
-
+
/* Allocation counts.. */
/**
static inline int d_unhashed(struct dentry *dentry)
{
- return (dentry->d_vfs_flags & DCACHE_UNHASHED);
+ return (dentry->d_flags & DCACHE_UNHASHED);
}
static inline struct dentry *dget_parent(struct dentry *dentry)
}
extern struct vfsmount *lookup_mnt(struct vfsmount *, struct dentry *);
+extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
+extern int sysctl_vfs_cache_pressure;
+
#endif /* __KERNEL__ */
#endif /* __LINUX_DCACHE_H */