diff options
Diffstat (limited to 'include/linux/fsnotify_backend.h')
| -rw-r--r-- | include/linux/fsnotify_backend.h | 96 | 
1 files changed, 87 insertions, 9 deletions
| diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 1ce66748a2d2..51ef2b079bfa 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -19,6 +19,7 @@  #include <linux/atomic.h>  #include <linux/user_namespace.h>  #include <linux/refcount.h> +#include <linux/mempool.h>  /*   * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily @@ -42,6 +43,12 @@  #define FS_UNMOUNT		0x00002000	/* inode on umount fs */  #define FS_Q_OVERFLOW		0x00004000	/* Event queued overflowed */ +#define FS_ERROR		0x00008000	/* Filesystem Error (fanotify) */ + +/* + * FS_IN_IGNORED overloads FS_ERROR.  It is only used internally by inotify + * which does not support FS_ERROR. + */  #define FS_IN_IGNORED		0x00008000	/* last inotify event here */  #define FS_OPEN_PERM		0x00010000	/* open event in an permission hook */ @@ -95,7 +102,8 @@  #define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \  			     FS_EVENTS_POSS_ON_CHILD | \  			     FS_DELETE_SELF | FS_MOVE_SELF | FS_DN_RENAME | \ -			     FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED) +			     FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ +			     FS_ERROR)  /* Extra flags that may be reported with event or control handling of events */  #define ALL_FSNOTIFY_FLAGS  (FS_EXCL_UNLINK | FS_ISDIR | FS_IN_ONESHOT | \ @@ -136,6 +144,7 @@ struct mem_cgroup;   * @dir:	optional directory associated with event -   *		if @file_name is not NULL, this is the directory that   *		@file_name is relative to. + *		Either @inode or @dir must be non-NULL.   * @file_name:	optional file name associated with event   * @cookie:	inotify rename cookie   * @@ -155,7 +164,7 @@ struct fsnotify_ops {  			    const struct qstr *file_name, u32 cookie);  	void (*free_group_priv)(struct fsnotify_group *group);  	void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group); -	void (*free_event)(struct fsnotify_event *event); +	void (*free_event)(struct fsnotify_group *group, struct fsnotify_event *event);  	/* called on final put+free to free memory */  	void (*free_mark)(struct fsnotify_mark *mark);  }; @@ -238,6 +247,7 @@ struct fsnotify_group {  			int flags;           /* flags from fanotify_init() */  			int f_flags; /* event_f_flags from fanotify_init() */  			struct ucounts *ucounts; +			mempool_t error_events_pool;  		} fanotify_data;  #endif /* CONFIG_FANOTIFY */  	}; @@ -248,6 +258,14 @@ enum fsnotify_data_type {  	FSNOTIFY_EVENT_NONE,  	FSNOTIFY_EVENT_PATH,  	FSNOTIFY_EVENT_INODE, +	FSNOTIFY_EVENT_DENTRY, +	FSNOTIFY_EVENT_ERROR, +}; + +struct fs_error_report { +	int error; +	struct inode *inode; +	struct super_block *sb;  };  static inline struct inode *fsnotify_data_inode(const void *data, int data_type) @@ -255,8 +273,25 @@ static inline struct inode *fsnotify_data_inode(const void *data, int data_type)  	switch (data_type) {  	case FSNOTIFY_EVENT_INODE:  		return (struct inode *)data; +	case FSNOTIFY_EVENT_DENTRY: +		return d_inode(data);  	case FSNOTIFY_EVENT_PATH:  		return d_inode(((const struct path *)data)->dentry); +	case FSNOTIFY_EVENT_ERROR: +		return ((struct fs_error_report *)data)->inode; +	default: +		return NULL; +	} +} + +static inline struct dentry *fsnotify_data_dentry(const void *data, int data_type) +{ +	switch (data_type) { +	case FSNOTIFY_EVENT_DENTRY: +		/* Non const is needed for dget() */ +		return (struct dentry *)data; +	case FSNOTIFY_EVENT_PATH: +		return ((const struct path *)data)->dentry;  	default:  		return NULL;  	} @@ -273,6 +308,35 @@ static inline const struct path *fsnotify_data_path(const void *data,  	}  } +static inline struct super_block *fsnotify_data_sb(const void *data, +						   int data_type) +{ +	switch (data_type) { +	case FSNOTIFY_EVENT_INODE: +		return ((struct inode *)data)->i_sb; +	case FSNOTIFY_EVENT_DENTRY: +		return ((struct dentry *)data)->d_sb; +	case FSNOTIFY_EVENT_PATH: +		return ((const struct path *)data)->dentry->d_sb; +	case FSNOTIFY_EVENT_ERROR: +		return ((struct fs_error_report *) data)->sb; +	default: +		return NULL; +	} +} + +static inline struct fs_error_report *fsnotify_data_error_report( +							const void *data, +							int data_type) +{ +	switch (data_type) { +	case FSNOTIFY_EVENT_ERROR: +		return (struct fs_error_report *) data; +	default: +		return NULL; +	} +} +  enum fsnotify_obj_type {  	FSNOTIFY_OBJ_TYPE_INODE,  	FSNOTIFY_OBJ_TYPE_PARENT, @@ -482,16 +546,30 @@ extern int fsnotify_fasync(int fd, struct file *file, int on);  extern void fsnotify_destroy_event(struct fsnotify_group *group,  				   struct fsnotify_event *event);  /* attach the event to the group notification queue */ -extern int fsnotify_add_event(struct fsnotify_group *group, -			      struct fsnotify_event *event, -			      int (*merge)(struct fsnotify_group *, -					   struct fsnotify_event *), -			      void (*insert)(struct fsnotify_group *, -					     struct fsnotify_event *)); +extern int fsnotify_insert_event(struct fsnotify_group *group, +				 struct fsnotify_event *event, +				 int (*merge)(struct fsnotify_group *, +					      struct fsnotify_event *), +				 void (*insert)(struct fsnotify_group *, +						struct fsnotify_event *)); + +static inline int fsnotify_add_event(struct fsnotify_group *group, +				     struct fsnotify_event *event, +				     int (*merge)(struct fsnotify_group *, +						  struct fsnotify_event *)) +{ +	return fsnotify_insert_event(group, event, merge, NULL); +} +  /* Queue overflow event to a notification group */  static inline void fsnotify_queue_overflow(struct fsnotify_group *group)  { -	fsnotify_add_event(group, group->overflow_event, NULL, NULL); +	fsnotify_add_event(group, group->overflow_event, NULL); +} + +static inline bool fsnotify_is_overflow_event(u32 mask) +{ +	return mask & FS_Q_OVERFLOW;  }  static inline bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) |