Commit 723c6e83 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] remove dparent_lock

The big SMP machines are seeing quite some contention in dnotify_parent()
(via vfs_write).  This function is hammering the global dparent_lock.

However we don't actually need a global dparent_lock for pinning down
dentry->d_parent.  We can use dentry->d_lock for this.  That is already being
held across d_move.

This patch speeds up SDET on the 16-way by 5% and wipes dnotify_parent() off
the profiles.

It also uninlines dnofity_parent().

It also uses spin_lock(), which is faster than read_lock().

I'm not sure that we need to take both the source and target dentry's d_lock
in d_move.

The patch also does lots of s/__inline__/inline/ in dcache.h
parent 1b8910cf
...@@ -208,10 +208,10 @@ had ->revalidate()) add calls in ->follow_link()/->readlink(). ...@@ -208,10 +208,10 @@ had ->revalidate()) add calls in ->follow_link()/->readlink().
if at least one of the following is true: if at least one of the following is true:
* filesystem has no cross-directory rename() * filesystem has no cross-directory rename()
* dcache_lock is held * dcache_lock is held
* dparent_lock is held (shared)
* we know that parent had been locked (e.g. we are looking at * we know that parent had been locked (e.g. we are looking at
->d_parent of ->lookup() argument). ->d_parent of ->lookup() argument).
* we are called from ->rename(). * we are called from ->rename().
* the child's ->d_lock is held
Audit your code and add locking if needed. Notice that any place that is Audit your code and add locking if needed. Notice that any place that is
not protected by the conditions above is risky even in the old tree - you not protected by the conditions above is risky even in the old tree - you
had been relying on BKL and that's prone to screwups. Old tree had quite had been relying on BKL and that's prone to screwups. Old tree had quite
......
...@@ -497,11 +497,7 @@ static int afs_d_revalidate(struct dentry *dentry, int flags) ...@@ -497,11 +497,7 @@ static int afs_d_revalidate(struct dentry *dentry, int flags)
_enter("%s,%x",dentry->d_name.name,flags); _enter("%s,%x",dentry->d_name.name,flags);
/* lock down the parent dentry so we can peer at it */ parent = dget_parent(dentry);
read_lock(&dparent_lock);
parent = dget(dentry->d_parent);
read_unlock(&dparent_lock);
dir = parent->d_inode; dir = parent->d_inode;
inode = dentry->d_inode; inode = dentry->d_inode;
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
/* #define DCACHE_DEBUG 1 */ /* #define DCACHE_DEBUG 1 */
spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
rwlock_t dparent_lock __cacheline_aligned_in_smp = RW_LOCK_UNLOCKED;
seqlock_t rename_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; seqlock_t rename_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
static kmem_cache_t *dentry_cache; static kmem_cache_t *dentry_cache;
...@@ -1205,7 +1204,16 @@ void d_move(struct dentry * dentry, struct dentry * target) ...@@ -1205,7 +1204,16 @@ void d_move(struct dentry * dentry, struct dentry * target)
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
write_seqlock(&rename_lock); write_seqlock(&rename_lock);
/*
* XXXX: do we really need to take target->d_lock?
*/
if (target < dentry) {
spin_lock(&target->d_lock);
spin_lock(&dentry->d_lock);
} else {
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
spin_lock(&target->d_lock);
}
/* Move the dentry to the target hash queue, if on different bucket */ /* Move the dentry to the target hash queue, if on different bucket */
if (dentry->d_bucket != target->d_bucket) { if (dentry->d_bucket != target->d_bucket) {
...@@ -1225,8 +1233,8 @@ void d_move(struct dentry * dentry, struct dentry * target) ...@@ -1225,8 +1233,8 @@ void d_move(struct dentry * dentry, struct dentry * target)
smp_wmb(); smp_wmb();
do_switch(dentry->d_name.len, target->d_name.len); do_switch(dentry->d_name.len, target->d_name.len);
do_switch(dentry->d_name.hash, target->d_name.hash); do_switch(dentry->d_name.hash, target->d_name.hash);
/* ... and switch the parents */ /* ... and switch the parents */
write_lock(&dparent_lock);
if (IS_ROOT(dentry)) { if (IS_ROOT(dentry)) {
dentry->d_parent = target->d_parent; dentry->d_parent = target->d_parent;
target->d_parent = target; target->d_parent = target;
...@@ -1237,10 +1245,10 @@ void d_move(struct dentry * dentry, struct dentry * target) ...@@ -1237,10 +1245,10 @@ void d_move(struct dentry * dentry, struct dentry * target)
/* And add them back to the (new) parent lists */ /* And add them back to the (new) parent lists */
list_add(&target->d_child, &target->d_parent->d_subdirs); list_add(&target->d_child, &target->d_parent->d_subdirs);
} }
write_unlock(&dparent_lock);
list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
dentry->d_move_count++; dentry->d_move_count++;
spin_unlock(&target->d_lock);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
write_sequnlock(&rename_lock); write_sequnlock(&rename_lock);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
......
...@@ -142,6 +142,29 @@ void __inode_dir_notify(struct inode *inode, unsigned long event) ...@@ -142,6 +142,29 @@ void __inode_dir_notify(struct inode *inode, unsigned long event)
write_unlock(&dn_lock); write_unlock(&dn_lock);
} }
/*
* This is hopelessly wrong, but unfixable without API changes. At
* least it doesn't oops the kernel...
*
* To safely access ->d_parent we need to keep d_move away from it. Use the
* dentry's d_lock for this.
*/
void dnotify_parent(struct dentry *dentry, unsigned long event)
{
struct dentry *parent;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent;
if (parent->d_inode->i_dnotify_mask & event) {
dget(parent);
spin_unlock(&dentry->d_lock);
__inode_dir_notify(parent->d_inode, event);
dput(parent);
} else {
spin_unlock(&dentry->d_lock);
}
}
static int __init dnotify_init(void) static int __init dnotify_init(void)
{ {
dn_cache = kmem_cache_create("dnotify_cache", dn_cache = kmem_cache_create("dnotify_cache",
......
...@@ -140,13 +140,20 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, ...@@ -140,13 +140,20 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
noprogress= 0; noprogress= 0;
while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) { while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) {
struct dentry *pd = target_dir; struct dentry *pd = target_dir;
read_lock(&dparent_lock);
while (!IS_ROOT(pd) &&
(pd->d_parent->d_flags & DCACHE_DISCONNECTED))
pd = pd->d_parent;
dget(pd); dget(pd);
read_unlock(&dparent_lock); spin_lock(&pd->d_lock);
while (!IS_ROOT(pd) &&
(pd->d_parent->d_flags&DCACHE_DISCONNECTED)) {
struct dentry *parent = pd->d_parent;
dget(parent);
spin_unlock(&pd->d_lock);
dput(pd);
pd = parent;
spin_lock(&pd->d_lock);
}
spin_unlock(&pd->d_lock);
if (!IS_ROOT(pd)) { if (!IS_ROOT(pd)) {
/* must have found a connected parent - great */ /* must have found a connected parent - great */
...@@ -469,11 +476,12 @@ static int export_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, ...@@ -469,11 +476,12 @@ static int export_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
fh[1] = inode->i_generation; fh[1] = inode->i_generation;
if (connectable && !S_ISDIR(inode->i_mode)) { if (connectable && !S_ISDIR(inode->i_mode)) {
struct inode *parent; struct inode *parent;
read_lock(&dparent_lock);
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode; parent = dentry->d_parent->d_inode;
fh[2] = parent->i_ino; fh[2] = parent->i_ino;
fh[3] = parent->i_generation; fh[3] = parent->i_generation;
read_unlock(&dparent_lock); spin_unlock(&dentry->d_lock);
len = 4; len = 4;
type = 2; type = 2;
} }
......
...@@ -624,9 +624,9 @@ int fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable) ...@@ -624,9 +624,9 @@ int fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
fh[1] = inode->i_generation; fh[1] = inode->i_generation;
fh[2] = MSDOS_I(inode)->i_location; fh[2] = MSDOS_I(inode)->i_location;
fh[3] = MSDOS_I(inode)->i_logstart; fh[3] = MSDOS_I(inode)->i_logstart;
read_lock(&dparent_lock); spin_lock(&de->d_lock);
fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart; fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart;
read_unlock(&dparent_lock); spin_unlock(&de->d_lock);
return 3; return 3;
} }
......
...@@ -273,9 +273,7 @@ __ncp_lookup_validate(struct dentry * dentry, int flags) ...@@ -273,9 +273,7 @@ __ncp_lookup_validate(struct dentry * dentry, int flags)
int res, val = 0, len = dentry->d_name.len + 1; int res, val = 0, len = dentry->d_name.len + 1;
__u8 __name[len]; __u8 __name[len];
read_lock(&dparent_lock); parent = dget_parent(dentry);
parent = dget(dentry->d_parent);
read_unlock(&dparent_lock);
dir = parent->d_inode; dir = parent->d_inode;
if (!dentry->d_inode) if (!dentry->d_inode)
......
...@@ -503,9 +503,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) ...@@ -503,9 +503,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
struct nfs_fh fhandle; struct nfs_fh fhandle;
struct nfs_fattr fattr; struct nfs_fattr fattr;
read_lock(&dparent_lock); parent = dget_parent(dentry);
parent = dget(dentry->d_parent);
read_unlock(&dparent_lock);
lock_kernel(); lock_kernel();
dir = parent->d_inode; dir = parent->d_inode;
inode = dentry->d_inode; inode = dentry->d_inode;
......
...@@ -545,9 +545,8 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, ...@@ -545,9 +545,8 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
while (exp == NULL && !IS_ROOT(dentry)) { while (exp == NULL && !IS_ROOT(dentry)) {
struct dentry *parent; struct dentry *parent;
read_lock(&dparent_lock);
parent = dget(dentry->d_parent); parent = dget_parent(dentry);
read_unlock(&dparent_lock);
dput(dentry); dput(dentry);
dentry = parent; dentry = parent;
exp = exp_get_by_name(clp, mnt, dentry, reqp); exp = exp_get_by_name(clp, mnt, dentry, reqp);
......
...@@ -820,9 +820,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, ...@@ -820,9 +820,7 @@ encode_entry(struct readdir_cd *ccd, const char *name,
fh_init(&fh, NFS3_FHSIZE); fh_init(&fh, NFS3_FHSIZE);
if (isdotent(name, namlen)) { if (isdotent(name, namlen)) {
if (namlen == 2) { if (namlen == 2) {
read_lock(&dparent_lock); dchild = dget_parent(dparent);
dchild = dget(dparent->d_parent);
read_unlock(&dparent_lock);
} else } else
dchild = dget(dparent); dchild = dget(dparent);
} else } else
......
...@@ -55,9 +55,7 @@ int nfsd_acceptable(void *expv, struct dentry *dentry) ...@@ -55,9 +55,7 @@ int nfsd_acceptable(void *expv, struct dentry *dentry)
while (tdentry != exp->ex_dentry && ! IS_ROOT(tdentry)) { while (tdentry != exp->ex_dentry && ! IS_ROOT(tdentry)) {
/* make sure parents give x permission to user */ /* make sure parents give x permission to user */
int err; int err;
read_lock(&dparent_lock); parent = dget_parent(tdentry);
parent = dget(tdentry->d_parent);
read_unlock(&dparent_lock);
err = permission(parent->d_inode, S_IXOTH); err = permission(parent->d_inode, S_IXOTH);
if (err < 0) { if (err < 0) {
dput(parent); dput(parent);
......
...@@ -112,9 +112,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -112,9 +112,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (len==1) if (len==1)
dentry = dget(dparent); dentry = dget(dparent);
else if (dparent != exp->ex_dentry) { else if (dparent != exp->ex_dentry) {
read_lock(&dparent_lock); dentry = dget_parent(dparent);
dentry = dget(dparent->d_parent);
read_unlock(&dparent_lock);
} else if (!EX_NOHIDE(exp)) } else if (!EX_NOHIDE(exp))
dentry = dget(dparent); /* .. == . just like at / */ dentry = dget(dparent); /* .. == . just like at / */
else { else {
...@@ -125,9 +123,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -125,9 +123,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dentry = dget(dparent); dentry = dget(dparent);
while(follow_up(&mnt, &dentry)) while(follow_up(&mnt, &dentry))
; ;
read_lock(&dparent_lock); dp = dget_parent(dentry);
dp = dget(dentry->d_parent);
read_unlock(&dparent_lock);
dput(dentry); dput(dentry);
dentry = dp; dentry = dp;
......
...@@ -241,7 +241,8 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent) ...@@ -241,7 +241,8 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
nls_name.hash = full_name_hash(nls_name.name, nls_name.len); nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
/* /*
* Note: No need for dparent_lock as i_sem is held on the parent inode. * Note: No need for dent->d_lock lock as i_sem is held on the
* parent inode.
*/ */
/* Does a dentry matching the nls_name exist already? */ /* Does a dentry matching the nls_name exist already? */
......
...@@ -1321,7 +1321,7 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_p ...@@ -1321,7 +1321,7 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_p
if (maxlen < 5 || ! need_parent) if (maxlen < 5 || ! need_parent)
return 3 ; return 3 ;
read_lock(&dparent_lock); spin_lock(&dentry->d_lock);
inode = dentry->d_parent->d_inode ; inode = dentry->d_parent->d_inode ;
data[3] = inode->i_ino ; data[3] = inode->i_ino ;
data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
...@@ -1330,7 +1330,7 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_p ...@@ -1330,7 +1330,7 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_p
data[5] = inode->i_generation ; data[5] = inode->i_generation ;
*lenp = 6 ; *lenp = 6 ;
} }
read_unlock(&dparent_lock); spin_unlock(&dentry->d_lock);
return *lenp ; return *lenp ;
} }
......
...@@ -400,14 +400,23 @@ smb_new_dentry(struct dentry *dentry) ...@@ -400,14 +400,23 @@ smb_new_dentry(struct dentry *dentry)
void void
smb_renew_times(struct dentry * dentry) smb_renew_times(struct dentry * dentry)
{ {
read_lock(&dparent_lock); dget(dentry);
spin_lock(&dentry->d_lock);
for (;;) { for (;;) {
struct dentry *parent;
dentry->d_time = jiffies; dentry->d_time = jiffies;
if (IS_ROOT(dentry)) if (IS_ROOT(dentry))
break; break;
dentry = dentry->d_parent; parent = dentry->d_parent;
dget(parent);
spin_unlock(&dentry->d_lock);
dput(dentry);
dentry = parent;
spin_lock(&dentry->d_lock);
} }
read_unlock(&dparent_lock); spin_unlock(&dentry->d_lock);
dput(dentry);
} }
static struct dentry * static struct dentry *
......
...@@ -333,10 +333,14 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf, ...@@ -333,10 +333,14 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
* Build the path string walking the tree backward from end to ROOT * Build the path string walking the tree backward from end to ROOT
* and store it in reversed order [see reverse_string()] * and store it in reversed order [see reverse_string()]
*/ */
read_lock(&dparent_lock); dget(entry);
spin_lock(&entry->d_lock);
while (!IS_ROOT(entry)) { while (!IS_ROOT(entry)) {
struct dentry *parent;
if (maxlen < (3<<unicode)) { if (maxlen < (3<<unicode)) {
read_unlock(&dparent_lock); spin_unlock(&entry->d_lock);
dput(entry);
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
...@@ -344,7 +348,8 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf, ...@@ -344,7 +348,8 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
entry->d_name.name, entry->d_name.len, entry->d_name.name, entry->d_name.len,
server->local_nls, server->remote_nls); server->local_nls, server->remote_nls);
if (len < 0) { if (len < 0) {
read_unlock(&dparent_lock); spin_unlock(&entry->d_lock);
dput(entry);
return len; return len;
} }
reverse_string(path, len); reverse_string(path, len);
...@@ -357,9 +362,15 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf, ...@@ -357,9 +362,15 @@ static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
*path++ = '\\'; *path++ = '\\';
maxlen -= len+1; maxlen -= len+1;
entry = entry->d_parent; parent = entry->d_parent;
dget(parent);
spin_unlock(&entry->d_lock);
dput(entry);
entry = parent;
spin_lock(&entry->d_lock);
} }
read_unlock(&dparent_lock); spin_unlock(&entry->d_lock);
dput(entry);
reverse_string(buf, path-buf); reverse_string(buf, path-buf);
/* maxlen has space for at least one char */ /* maxlen has space for at least one char */
......
...@@ -48,19 +48,24 @@ extern struct dentry_stat_t dentry_stat; ...@@ -48,19 +48,24 @@ extern struct dentry_stat_t dentry_stat;
#define init_name_hash() 0 #define init_name_hash() 0
/* partial hash update function. Assume roughly 4 bits per character */ /* partial hash update function. Assume roughly 4 bits per character */
static __inline__ unsigned long partial_name_hash(unsigned long c, unsigned long prevhash) static inline unsigned long
partial_name_hash(unsigned long c, unsigned long prevhash)
{ {
return (prevhash + (c << 4) + (c >> 4)) * 11; return (prevhash + (c << 4) + (c >> 4)) * 11;
} }
/* Finally: cut down the number of bits to a int value (and try to avoid losing bits) */ /*
static __inline__ unsigned long end_name_hash(unsigned long hash) * Finally: cut down the number of bits to a int value (and try to avoid
* losing bits)
*/
static inline unsigned long end_name_hash(unsigned long hash)
{ {
return (unsigned int) hash; return (unsigned int) hash;
} }
/* Compute the hash for a name string. */ /* Compute the hash for a name string. */
static __inline__ unsigned int full_name_hash(const unsigned char * name, unsigned int len) static inline unsigned int
full_name_hash(const unsigned char *name, unsigned int len)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash();
while (len--) while (len--)
...@@ -149,7 +154,6 @@ d_iput: no no yes ...@@ -149,7 +154,6 @@ d_iput: no no yes
#define DCACHE_UNHASHED 0x0010 #define DCACHE_UNHASHED 0x0010
extern spinlock_t dcache_lock; extern spinlock_t dcache_lock;
extern rwlock_t dparent_lock;
/** /**
* d_drop - drop a dentry * d_drop - drop a dentry
...@@ -168,20 +172,20 @@ extern rwlock_t dparent_lock; ...@@ -168,20 +172,20 @@ extern rwlock_t dparent_lock;
* timeouts or autofs deletes). * timeouts or autofs deletes).
*/ */
static __inline__ void __d_drop(struct dentry * dentry) static inline void __d_drop(struct dentry *dentry)
{ {
dentry->d_vfs_flags |= DCACHE_UNHASHED; dentry->d_vfs_flags |= DCACHE_UNHASHED;
hlist_del_rcu(&dentry->d_hash); hlist_del_rcu(&dentry->d_hash);
} }
static __inline__ void d_drop(struct dentry * dentry) static inline void d_drop(struct dentry *dentry)
{ {
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
static __inline__ int dname_external(struct dentry *d) static inline int dname_external(struct dentry *d)
{ {
return d->d_name.name != d->d_iname; return d->d_name.name != d->d_iname;
} }
...@@ -227,7 +231,7 @@ extern void d_rehash(struct dentry *); ...@@ -227,7 +231,7 @@ extern void d_rehash(struct dentry *);
* The entry was actually filled in earlier during d_alloc(). * The entry was actually filled in earlier during d_alloc().
*/ */
static __inline__ void d_add(struct dentry * entry, struct inode * inode) static inline void d_add(struct dentry *entry, struct inode *inode)
{ {
d_instantiate(entry, inode); d_instantiate(entry, inode);
d_rehash(entry); d_rehash(entry);
...@@ -260,7 +264,7 @@ extern char * d_path(struct dentry *, struct vfsmount *, char *, int); ...@@ -260,7 +264,7 @@ extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
* and call dget_locked() instead of dget(). * and call dget_locked() instead of dget().
*/ */
static __inline__ struct dentry * dget(struct dentry *dentry) static inline struct dentry *dget(struct dentry *dentry)
{ {
if (dentry) { if (dentry) {
if (!atomic_read(&dentry->d_count)) if (!atomic_read(&dentry->d_count))
...@@ -280,14 +284,24 @@ extern struct dentry * dget_locked(struct dentry *); ...@@ -280,14 +284,24 @@ extern struct dentry * dget_locked(struct dentry *);
* 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(struct dentry *dentry) static inline int d_unhashed(struct dentry *dentry)
{ {
return (dentry->d_vfs_flags & DCACHE_UNHASHED); return (dentry->d_vfs_flags & DCACHE_UNHASHED);
} }
static inline struct dentry *dget_parent(struct dentry *dentry)
{
struct dentry *ret;
spin_lock(&dentry->d_lock);
ret = dget(dentry->d_parent);
spin_unlock(&dentry->d_lock);
return ret;
}
extern void dput(struct dentry *); extern void dput(struct dentry *);
static __inline__ int d_mountpoint(struct dentry *dentry) static inline int d_mountpoint(struct dentry *dentry)
{ {
return dentry->d_mounted; return dentry->d_mounted;
} }
......
...@@ -18,27 +18,10 @@ struct dnotify_struct { ...@@ -18,27 +18,10 @@ struct dnotify_struct {
extern void __inode_dir_notify(struct inode *, unsigned long); extern void __inode_dir_notify(struct inode *, unsigned long);
extern void dnotify_flush(struct file *filp, fl_owner_t id); extern void dnotify_flush(struct file *filp, fl_owner_t id);
extern int fcntl_dirnotify(int, struct file *, unsigned long); extern int fcntl_dirnotify(int, struct file *, unsigned long);
void dnotify_parent(struct dentry *dentry, unsigned long event);
static inline void inode_dir_notify(struct inode *inode, unsigned long event) static inline void inode_dir_notify(struct inode *inode, unsigned long event)
{ {
if ((inode)->i_dnotify_mask & (event)) if ((inode)->i_dnotify_mask & (event))
__inode_dir_notify(inode, event); __inode_dir_notify(inode, event);
} }
/*
* This is hopelessly wrong, but unfixable without API changes. At
* least it doesn't oops the kernel...
*/
static inline void dnotify_parent(struct dentry *dentry, unsigned long event)
{
struct dentry *parent;
read_lock(&dparent_lock);
parent = dentry->d_parent;
if (parent->d_inode->i_dnotify_mask & event) {
dget(parent);
read_unlock(&dparent_lock);
__inode_dir_notify(parent->d_inode, event);
dput(parent);
} else
read_unlock(&dparent_lock);
}
...@@ -1306,9 +1306,10 @@ extern void inode_update_time(struct inode *inode, int ctime_too); ...@@ -1306,9 +1306,10 @@ extern void inode_update_time(struct inode *inode, int ctime_too);
static inline ino_t parent_ino(struct dentry *dentry) static inline ino_t parent_ino(struct dentry *dentry)
{ {
ino_t res; ino_t res;
read_lock(&dparent_lock);
spin_lock(&dentry->d_lock);
res = dentry->d_parent->d_inode->i_ino; res = dentry->d_parent->d_inode->i_ino;
read_unlock(&dparent_lock); spin_unlock(&dentry->d_lock);
return res; return res;
} }
......
...@@ -159,7 +159,6 @@ EXPORT_SYMBOL(lookup_one_len); ...@@ -159,7 +159,6 @@ EXPORT_SYMBOL(lookup_one_len);
EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(lookup_hash);
EXPORT_SYMBOL(sys_close); EXPORT_SYMBOL(sys_close);
EXPORT_SYMBOL(dcache_lock); EXPORT_SYMBOL(dcache_lock);
EXPORT_SYMBOL(dparent_lock);
EXPORT_SYMBOL(d_alloc_root); EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete); EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(dget_locked); EXPORT_SYMBOL(dget_locked);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment