diff options
| author | Alexander Viro <viro@math.psu.edu> | 2002-02-17 16:35:06 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-02-17 16:35:06 -0800 |
| commit | 222099f6c32004454f8c44ade53135adc2e1b179 (patch) | |
| tree | 0ee50c85c5e82808b005e11f0812287666a2f4c6 /include/linux | |
| parent | cb625b80c8ee31f556250b055224249ed89fe3bd (diff) | |
[PATCH] dnotify race fix
A bunch of places dereferences ->d_parent->d_inode with no
protection whatsoever (e.g. on return from read()). It's an
SMP race on all boxen and pretty wide UP race if we have dnotify
set on parent (race between read() and rename() and similar beasts).
Patch below is the first one in a series of ->d_parent-related
fixes. It adds a helper (dnotify_parent(dentry, event)) and converts
places that did inode_dir_notify(dentry->d_parent->d_inode,...) to it.
Please, apply. Notice that problem exists in 2.4 and unlike 2.5
there we can't switch to saner API (basically, reporting file events on
file, not on a parent directory).
Some of the further fixes depend on Pat's and Greg's (driverfs and usbdevfs
resp.) patches, so getting them merged would make life easier. And yes,
some of further chunks (e.g. smbfs ->revalidate() and friends) will also
have to go into 2.4 - they are independent from any threading projects ;-/
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/dnotify.h | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/include/linux/dnotify.h b/include/linux/dnotify.h index 90813c505064..794fd096f31f 100644 --- a/include/linux/dnotify.h +++ b/include/linux/dnotify.h @@ -25,3 +25,21 @@ static inline void inode_dir_notify(struct inode *inode, unsigned long event) if ((inode)->i_dnotify_mask & (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; + spin_lock(&dcache_lock); + parent = dentry->d_parent; + if (parent->d_inode->i_dnotify_mask & event) { + dget(parent); + spin_unlock(&dcache_lock); + __inode_dir_notify(parent->d_inode, event); + dput(parent); + } else + spin_unlock(&dcache_lock); +} |
