fsnotify: invalidate dcache before IN_DELETE event
[linux-2.6-microblaze.git] / include / linux / fsnotify.h
index 787545e..bb8467c 100644 (file)
@@ -144,16 +144,19 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
        u32 fs_cookie = fsnotify_get_cookie();
        __u32 old_dir_mask = FS_MOVED_FROM;
        __u32 new_dir_mask = FS_MOVED_TO;
+       __u32 rename_mask = FS_RENAME;
        const struct qstr *new_name = &moved->d_name;
 
-       if (old_dir == new_dir)
-               old_dir_mask |= FS_DN_RENAME;
-
        if (isdir) {
                old_dir_mask |= FS_ISDIR;
                new_dir_mask |= FS_ISDIR;
+               rename_mask |= FS_ISDIR;
        }
 
+       /* Event with information about both old and new parent+name */
+       fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY,
+                     old_dir, old_name, 0);
+
        fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE,
                      old_dir, old_name, fs_cookie);
        fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE,
@@ -221,6 +224,43 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
                      dir, &new_dentry->d_name, 0);
 }
 
+/*
+ * fsnotify_delete - @dentry was unlinked and unhashed
+ *
+ * Caller must make sure that dentry->d_name is stable.
+ *
+ * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode
+ * as this may be called after d_delete() and old_dentry may be negative.
+ */
+static inline void fsnotify_delete(struct inode *dir, struct inode *inode,
+                                  struct dentry *dentry)
+{
+       __u32 mask = FS_DELETE;
+
+       if (S_ISDIR(inode->i_mode))
+               mask |= FS_ISDIR;
+
+       fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name,
+                     0);
+}
+
+/**
+ * d_delete_notify - delete a dentry and call fsnotify_delete()
+ * @dentry: The dentry to delete
+ *
+ * This helper is used to guaranty that the unlinked inode cannot be found
+ * by lookup of this name after fsnotify_delete() event has been delivered.
+ */
+static inline void d_delete_notify(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+
+       ihold(inode);
+       d_delete(dentry);
+       fsnotify_delete(dir, inode, dentry);
+       iput(inode);
+}
+
 /*
  * fsnotify_unlink - 'name' was unlinked
  *
@@ -228,10 +268,10 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
  */
 static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
 {
-       /* Expected to be called before d_delete() */
-       WARN_ON_ONCE(d_is_negative(dentry));
+       if (WARN_ON_ONCE(d_is_negative(dentry)))
+               return;
 
-       fsnotify_dirent(dir, dentry, FS_DELETE);
+       fsnotify_delete(dir, d_inode(dentry), dentry);
 }
 
 /*
@@ -255,10 +295,10 @@ static inline void fsnotify_mkdir(struct inode *dir, struct dentry *dentry)
  */
 static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       /* Expected to be called before d_delete() */
-       WARN_ON_ONCE(d_is_negative(dentry));
+       if (WARN_ON_ONCE(d_is_negative(dentry)))
+               return;
 
-       fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
+       fsnotify_delete(dir, d_inode(dentry), dentry);
 }
 
 /*