summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAlexander Viro <viro@math.psu.edu>2002-02-17 16:35:06 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-02-17 16:35:06 -0800
commit222099f6c32004454f8c44ade53135adc2e1b179 (patch)
tree0ee50c85c5e82808b005e11f0812287666a2f4c6 /include/linux
parentcb625b80c8ee31f556250b055224249ed89fe3bd (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.h18
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);
+}