xref: /openbmc/linux/fs/notify/fanotify/fanotify.h (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
27053aee2SJan Kara #include <linux/fsnotify_backend.h>
37053aee2SJan Kara #include <linux/path.h>
47053aee2SJan Kara #include <linux/slab.h>
5e9e0c890SAmir Goldstein #include <linux/exportfs.h>
694e00d28SAmir Goldstein #include <linux/hashtable.h>
77053aee2SJan Kara 
8054c636eSJan Kara extern struct kmem_cache *fanotify_mark_cache;
97088f357SJan Kara extern struct kmem_cache *fanotify_fid_event_cachep;
107088f357SJan Kara extern struct kmem_cache *fanotify_path_event_cachep;
11f083441bSJan Kara extern struct kmem_cache *fanotify_perm_event_cachep;
127053aee2SJan Kara 
1340873284SJan Kara /* Possible states of the permission event */
1440873284SJan Kara enum {
1540873284SJan Kara 	FAN_EVENT_INIT,
1640873284SJan Kara 	FAN_EVENT_REPORTED,
17fabf7f29SJan Kara 	FAN_EVENT_ANSWERED,
18fabf7f29SJan Kara 	FAN_EVENT_CANCELED,
1940873284SJan Kara };
2040873284SJan Kara 
2185816794SJan Kara /*
22e9e0c890SAmir Goldstein  * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation).
23afc894c7SJan Kara  * fh buf should be dword aligned. On 64bit arch, the ext_buf pointer is
24afc894c7SJan Kara  * stored in either the first or last 2 dwords.
25e9e0c890SAmir Goldstein  */
26e9e0c890SAmir Goldstein #define FANOTIFY_INLINE_FH_LEN	(3 << 2)
27f454fa61SAmir Goldstein #define FANOTIFY_FH_HDR_LEN	offsetof(struct fanotify_fh, buf)
28e9e0c890SAmir Goldstein 
29f454fa61SAmir Goldstein /* Fixed size struct for file handle */
30afc894c7SJan Kara struct fanotify_fh {
31afc894c7SJan Kara 	u8 type;
32afc894c7SJan Kara 	u8 len;
33f35c4156SAmir Goldstein #define FANOTIFY_FH_FLAG_EXT_BUF 1
34f35c4156SAmir Goldstein 	u8 flags;
35f35c4156SAmir Goldstein 	u8 pad;
36f35c4156SAmir Goldstein 	unsigned char buf[];
37f454fa61SAmir Goldstein } __aligned(4);
38f454fa61SAmir Goldstein 
39f454fa61SAmir Goldstein /* Variable size struct for dir file handle + child file handle + name */
40f454fa61SAmir Goldstein struct fanotify_info {
41f454fa61SAmir Goldstein 	/* size of dir_fh/file_fh including fanotify_fh hdr size */
42f454fa61SAmir Goldstein 	u8 dir_fh_totlen;
433cf984e9SAmir Goldstein 	u8 dir2_fh_totlen;
44f454fa61SAmir Goldstein 	u8 file_fh_totlen;
45f454fa61SAmir Goldstein 	u8 name_len;
463cf984e9SAmir Goldstein 	u8 name2_len;
473cf984e9SAmir Goldstein 	u8 pad[3];
48f454fa61SAmir Goldstein 	unsigned char buf[];
49f454fa61SAmir Goldstein 	/*
50f454fa61SAmir Goldstein 	 * (struct fanotify_fh) dir_fh starts at buf[0]
513cf984e9SAmir Goldstein 	 * (optional) dir2_fh starts at buf[dir_fh_totlen]
523cf984e9SAmir Goldstein 	 * (optional) file_fh starts at buf[dir_fh_totlen + dir2_fh_totlen]
533cf984e9SAmir Goldstein 	 * name starts at buf[dir_fh_totlen + dir2_fh_totlen + file_fh_totlen]
543cf984e9SAmir Goldstein 	 * ...
55f454fa61SAmir Goldstein 	 */
562d9374f0SAmir Goldstein #define FANOTIFY_DIR_FH_SIZE(info)	((info)->dir_fh_totlen)
573cf984e9SAmir Goldstein #define FANOTIFY_DIR2_FH_SIZE(info)	((info)->dir2_fh_totlen)
582d9374f0SAmir Goldstein #define FANOTIFY_FILE_FH_SIZE(info)	((info)->file_fh_totlen)
592d9374f0SAmir Goldstein #define FANOTIFY_NAME_SIZE(info)	((info)->name_len + 1)
603cf984e9SAmir Goldstein #define FANOTIFY_NAME2_SIZE(info)	((info)->name2_len + 1)
612d9374f0SAmir Goldstein 
622d9374f0SAmir Goldstein #define FANOTIFY_DIR_FH_OFFSET(info)	0
633cf984e9SAmir Goldstein #define FANOTIFY_DIR2_FH_OFFSET(info) \
642d9374f0SAmir Goldstein 	(FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info))
653cf984e9SAmir Goldstein #define FANOTIFY_FILE_FH_OFFSET(info) \
663cf984e9SAmir Goldstein 	(FANOTIFY_DIR2_FH_OFFSET(info) + FANOTIFY_DIR2_FH_SIZE(info))
672d9374f0SAmir Goldstein #define FANOTIFY_NAME_OFFSET(info) \
682d9374f0SAmir Goldstein 	(FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info))
693cf984e9SAmir Goldstein #define FANOTIFY_NAME2_OFFSET(info) \
703cf984e9SAmir Goldstein 	(FANOTIFY_NAME_OFFSET(info) + FANOTIFY_NAME_SIZE(info))
712d9374f0SAmir Goldstein 
722d9374f0SAmir Goldstein #define FANOTIFY_DIR_FH_BUF(info) \
732d9374f0SAmir Goldstein 	((info)->buf + FANOTIFY_DIR_FH_OFFSET(info))
743cf984e9SAmir Goldstein #define FANOTIFY_DIR2_FH_BUF(info) \
753cf984e9SAmir Goldstein 	((info)->buf + FANOTIFY_DIR2_FH_OFFSET(info))
762d9374f0SAmir Goldstein #define FANOTIFY_FILE_FH_BUF(info) \
772d9374f0SAmir Goldstein 	((info)->buf + FANOTIFY_FILE_FH_OFFSET(info))
782d9374f0SAmir Goldstein #define FANOTIFY_NAME_BUF(info) \
792d9374f0SAmir Goldstein 	((info)->buf + FANOTIFY_NAME_OFFSET(info))
803cf984e9SAmir Goldstein #define FANOTIFY_NAME2_BUF(info) \
813cf984e9SAmir Goldstein 	((info)->buf + FANOTIFY_NAME2_OFFSET(info))
82afc894c7SJan Kara } __aligned(4);
83e9e0c890SAmir Goldstein 
fanotify_fh_has_ext_buf(struct fanotify_fh * fh)84afc894c7SJan Kara static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh)
85e9e0c890SAmir Goldstein {
86f35c4156SAmir Goldstein 	return (fh->flags & FANOTIFY_FH_FLAG_EXT_BUF);
87e9e0c890SAmir Goldstein }
88e9e0c890SAmir Goldstein 
fanotify_fh_ext_buf_ptr(struct fanotify_fh * fh)89afc894c7SJan Kara static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh)
90e9e0c890SAmir Goldstein {
91f454fa61SAmir Goldstein 	BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN % 4);
92afc894c7SJan Kara 	BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) >
93afc894c7SJan Kara 		     FANOTIFY_INLINE_FH_LEN);
94afc894c7SJan Kara 	return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *));
95afc894c7SJan Kara }
96afc894c7SJan Kara 
fanotify_fh_ext_buf(struct fanotify_fh * fh)97afc894c7SJan Kara static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh)
98afc894c7SJan Kara {
99afc894c7SJan Kara 	return *fanotify_fh_ext_buf_ptr(fh);
100afc894c7SJan Kara }
101afc894c7SJan Kara 
fanotify_fh_buf(struct fanotify_fh * fh)102afc894c7SJan Kara static inline void *fanotify_fh_buf(struct fanotify_fh *fh)
103afc894c7SJan Kara {
104afc894c7SJan Kara 	return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf;
105e9e0c890SAmir Goldstein }
106e9e0c890SAmir Goldstein 
fanotify_info_dir_fh_len(struct fanotify_info * info)107f454fa61SAmir Goldstein static inline int fanotify_info_dir_fh_len(struct fanotify_info *info)
108f454fa61SAmir Goldstein {
109f454fa61SAmir Goldstein 	if (!info->dir_fh_totlen ||
110f454fa61SAmir Goldstein 	    WARN_ON_ONCE(info->dir_fh_totlen < FANOTIFY_FH_HDR_LEN))
111f454fa61SAmir Goldstein 		return 0;
112f454fa61SAmir Goldstein 
113f454fa61SAmir Goldstein 	return info->dir_fh_totlen - FANOTIFY_FH_HDR_LEN;
114f454fa61SAmir Goldstein }
115f454fa61SAmir Goldstein 
fanotify_info_dir_fh(struct fanotify_info * info)116f454fa61SAmir Goldstein static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *info)
117f454fa61SAmir Goldstein {
118f454fa61SAmir Goldstein 	BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4);
119f454fa61SAmir Goldstein 
1202d9374f0SAmir Goldstein 	return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info);
121f454fa61SAmir Goldstein }
122f454fa61SAmir Goldstein 
fanotify_info_dir2_fh_len(struct fanotify_info * info)1233cf984e9SAmir Goldstein static inline int fanotify_info_dir2_fh_len(struct fanotify_info *info)
1243cf984e9SAmir Goldstein {
1253cf984e9SAmir Goldstein 	if (!info->dir2_fh_totlen ||
1263cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->dir2_fh_totlen < FANOTIFY_FH_HDR_LEN))
1273cf984e9SAmir Goldstein 		return 0;
1283cf984e9SAmir Goldstein 
1293cf984e9SAmir Goldstein 	return info->dir2_fh_totlen - FANOTIFY_FH_HDR_LEN;
1303cf984e9SAmir Goldstein }
1313cf984e9SAmir Goldstein 
fanotify_info_dir2_fh(struct fanotify_info * info)1323cf984e9SAmir Goldstein static inline struct fanotify_fh *fanotify_info_dir2_fh(struct fanotify_info *info)
1333cf984e9SAmir Goldstein {
1343cf984e9SAmir Goldstein 	return (struct fanotify_fh *)FANOTIFY_DIR2_FH_BUF(info);
1353cf984e9SAmir Goldstein }
1363cf984e9SAmir Goldstein 
fanotify_info_file_fh_len(struct fanotify_info * info)137f454fa61SAmir Goldstein static inline int fanotify_info_file_fh_len(struct fanotify_info *info)
138f454fa61SAmir Goldstein {
139f454fa61SAmir Goldstein 	if (!info->file_fh_totlen ||
140f454fa61SAmir Goldstein 	    WARN_ON_ONCE(info->file_fh_totlen < FANOTIFY_FH_HDR_LEN))
141f454fa61SAmir Goldstein 		return 0;
142f454fa61SAmir Goldstein 
143f454fa61SAmir Goldstein 	return info->file_fh_totlen - FANOTIFY_FH_HDR_LEN;
144f454fa61SAmir Goldstein }
145f454fa61SAmir Goldstein 
fanotify_info_file_fh(struct fanotify_info * info)146f454fa61SAmir Goldstein static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info)
147f454fa61SAmir Goldstein {
1482d9374f0SAmir Goldstein 	return (struct fanotify_fh *)FANOTIFY_FILE_FH_BUF(info);
149f454fa61SAmir Goldstein }
150f454fa61SAmir Goldstein 
fanotify_info_name(struct fanotify_info * info)1512d9374f0SAmir Goldstein static inline char *fanotify_info_name(struct fanotify_info *info)
152f454fa61SAmir Goldstein {
1532d9374f0SAmir Goldstein 	if (!info->name_len)
1542d9374f0SAmir Goldstein 		return NULL;
1552d9374f0SAmir Goldstein 
1562d9374f0SAmir Goldstein 	return FANOTIFY_NAME_BUF(info);
157f454fa61SAmir Goldstein }
158f454fa61SAmir Goldstein 
fanotify_info_name2(struct fanotify_info * info)1593cf984e9SAmir Goldstein static inline char *fanotify_info_name2(struct fanotify_info *info)
1603cf984e9SAmir Goldstein {
1613cf984e9SAmir Goldstein 	if (!info->name2_len)
1623cf984e9SAmir Goldstein 		return NULL;
1633cf984e9SAmir Goldstein 
1643cf984e9SAmir Goldstein 	return FANOTIFY_NAME2_BUF(info);
1653cf984e9SAmir Goldstein }
1663cf984e9SAmir Goldstein 
fanotify_info_init(struct fanotify_info * info)167f454fa61SAmir Goldstein static inline void fanotify_info_init(struct fanotify_info *info)
168f454fa61SAmir Goldstein {
1692d9374f0SAmir Goldstein 	BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX);
1702d9374f0SAmir Goldstein 	BUILD_BUG_ON(NAME_MAX > U8_MAX);
1712d9374f0SAmir Goldstein 
172f454fa61SAmir Goldstein 	info->dir_fh_totlen = 0;
1733cf984e9SAmir Goldstein 	info->dir2_fh_totlen = 0;
174f454fa61SAmir Goldstein 	info->file_fh_totlen = 0;
175f454fa61SAmir Goldstein 	info->name_len = 0;
1763cf984e9SAmir Goldstein 	info->name2_len = 0;
177f454fa61SAmir Goldstein }
178f454fa61SAmir Goldstein 
1791a9515acSAmir Goldstein /* These set/copy helpers MUST be called by order */
fanotify_info_set_dir_fh(struct fanotify_info * info,unsigned int totlen)1801a9515acSAmir Goldstein static inline void fanotify_info_set_dir_fh(struct fanotify_info *info,
1811a9515acSAmir Goldstein 					    unsigned int totlen)
1821a9515acSAmir Goldstein {
1833cf984e9SAmir Goldstein 	if (WARN_ON_ONCE(info->dir2_fh_totlen > 0) ||
1843cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->file_fh_totlen > 0) ||
1853cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->name_len > 0) ||
1863cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->name2_len > 0))
1871a9515acSAmir Goldstein 		return;
1881a9515acSAmir Goldstein 
1891a9515acSAmir Goldstein 	info->dir_fh_totlen = totlen;
1901a9515acSAmir Goldstein }
1911a9515acSAmir Goldstein 
fanotify_info_set_dir2_fh(struct fanotify_info * info,unsigned int totlen)1923cf984e9SAmir Goldstein static inline void fanotify_info_set_dir2_fh(struct fanotify_info *info,
1933cf984e9SAmir Goldstein 					     unsigned int totlen)
1943cf984e9SAmir Goldstein {
1953cf984e9SAmir Goldstein 	if (WARN_ON_ONCE(info->file_fh_totlen > 0) ||
1963cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->name_len > 0) ||
1973cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->name2_len > 0))
1983cf984e9SAmir Goldstein 		return;
1993cf984e9SAmir Goldstein 
2003cf984e9SAmir Goldstein 	info->dir2_fh_totlen = totlen;
2013cf984e9SAmir Goldstein }
2023cf984e9SAmir Goldstein 
fanotify_info_set_file_fh(struct fanotify_info * info,unsigned int totlen)2031a9515acSAmir Goldstein static inline void fanotify_info_set_file_fh(struct fanotify_info *info,
2041a9515acSAmir Goldstein 					     unsigned int totlen)
2051a9515acSAmir Goldstein {
2063cf984e9SAmir Goldstein 	if (WARN_ON_ONCE(info->name_len > 0) ||
2073cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->name2_len > 0))
2081a9515acSAmir Goldstein 		return;
2091a9515acSAmir Goldstein 
2101a9515acSAmir Goldstein 	info->file_fh_totlen = totlen;
2111a9515acSAmir Goldstein }
2121a9515acSAmir Goldstein 
fanotify_info_copy_name(struct fanotify_info * info,const struct qstr * name)213f454fa61SAmir Goldstein static inline void fanotify_info_copy_name(struct fanotify_info *info,
214f454fa61SAmir Goldstein 					   const struct qstr *name)
215f454fa61SAmir Goldstein {
2163cf984e9SAmir Goldstein 	if (WARN_ON_ONCE(name->len > NAME_MAX) ||
2173cf984e9SAmir Goldstein 	    WARN_ON_ONCE(info->name2_len > 0))
2182d9374f0SAmir Goldstein 		return;
2192d9374f0SAmir Goldstein 
220f454fa61SAmir Goldstein 	info->name_len = name->len;
2212d9374f0SAmir Goldstein 	strcpy(fanotify_info_name(info), name->name);
222f454fa61SAmir Goldstein }
223f454fa61SAmir Goldstein 
fanotify_info_copy_name2(struct fanotify_info * info,const struct qstr * name)2243cf984e9SAmir Goldstein static inline void fanotify_info_copy_name2(struct fanotify_info *info,
2253cf984e9SAmir Goldstein 					    const struct qstr *name)
2263cf984e9SAmir Goldstein {
2273cf984e9SAmir Goldstein 	if (WARN_ON_ONCE(name->len > NAME_MAX))
2283cf984e9SAmir Goldstein 		return;
2293cf984e9SAmir Goldstein 
2303cf984e9SAmir Goldstein 	info->name2_len = name->len;
2313cf984e9SAmir Goldstein 	strcpy(fanotify_info_name2(info), name->name);
2323cf984e9SAmir Goldstein }
2333cf984e9SAmir Goldstein 
234e9e0c890SAmir Goldstein /*
2357088f357SJan Kara  * Common structure for fanotify events. Concrete structs are allocated in
236f083441bSJan Kara  * fanotify_handle_event() and freed when the information is retrieved by
2377088f357SJan Kara  * userspace. The type of event determines how it was allocated, how it will
2387088f357SJan Kara  * be freed and which concrete struct it may be cast to.
23985816794SJan Kara  */
2407088f357SJan Kara enum fanotify_event_type {
241cacfb956SAmir Goldstein 	FANOTIFY_EVENT_TYPE_FID, /* fixed length */
242cacfb956SAmir Goldstein 	FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */
2437088f357SJan Kara 	FANOTIFY_EVENT_TYPE_PATH,
2447088f357SJan Kara 	FANOTIFY_EVENT_TYPE_PATH_PERM,
245b8a6c3a2SAmir Goldstein 	FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */
246734a1a5eSGabriel Krisman Bertazi 	FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */
2478988f11aSAmir Goldstein 	__FANOTIFY_EVENT_TYPE_NUM
2487088f357SJan Kara };
2497088f357SJan Kara 
2508988f11aSAmir Goldstein #define FANOTIFY_EVENT_TYPE_BITS \
2518988f11aSAmir Goldstein 	(ilog2(__FANOTIFY_EVENT_TYPE_NUM - 1) + 1)
2528988f11aSAmir Goldstein #define FANOTIFY_EVENT_HASH_BITS \
2538988f11aSAmir Goldstein 	(32 - FANOTIFY_EVENT_TYPE_BITS)
2548988f11aSAmir Goldstein 
25533913997SAmir Goldstein struct fanotify_event {
2567053aee2SJan Kara 	struct fsnotify_event fse;
25794e00d28SAmir Goldstein 	struct hlist_node merge_list;	/* List for hashed merge */
258a0a92d26SAmir Goldstein 	u32 mask;
2598988f11aSAmir Goldstein 	struct {
2608988f11aSAmir Goldstein 		unsigned int type : FANOTIFY_EVENT_TYPE_BITS;
2618988f11aSAmir Goldstein 		unsigned int hash : FANOTIFY_EVENT_HASH_BITS;
2628988f11aSAmir Goldstein 	};
263d0a6a87eSAmir Goldstein 	struct pid *pid;
2647053aee2SJan Kara };
2657053aee2SJan Kara 
fanotify_init_event(struct fanotify_event * event,unsigned int hash,u32 mask)266b8a6c3a2SAmir Goldstein static inline void fanotify_init_event(struct fanotify_event *event,
2678988f11aSAmir Goldstein 				       unsigned int hash, u32 mask)
268b8a6c3a2SAmir Goldstein {
2698988f11aSAmir Goldstein 	fsnotify_init_event(&event->fse);
27094e00d28SAmir Goldstein 	INIT_HLIST_NODE(&event->merge_list);
2718988f11aSAmir Goldstein 	event->hash = hash;
272b8a6c3a2SAmir Goldstein 	event->mask = mask;
273b8a6c3a2SAmir Goldstein 	event->pid = NULL;
274b8a6c3a2SAmir Goldstein }
275b8a6c3a2SAmir Goldstein 
2762c506943SGabriel Krisman Bertazi #define FANOTIFY_INLINE_FH(name, size)					\
2772c506943SGabriel Krisman Bertazi struct {								\
2782c506943SGabriel Krisman Bertazi 	struct fanotify_fh (name);					\
2792c506943SGabriel Krisman Bertazi 	/* Space for object_fh.buf[] - access with fanotify_fh_buf() */	\
2802c506943SGabriel Krisman Bertazi 	unsigned char _inline_fh_buf[(size)];				\
2812c506943SGabriel Krisman Bertazi }
2822c506943SGabriel Krisman Bertazi 
2837088f357SJan Kara struct fanotify_fid_event {
2847088f357SJan Kara 	struct fanotify_event fae;
2857088f357SJan Kara 	__kernel_fsid_t fsid;
2862c506943SGabriel Krisman Bertazi 
2872c506943SGabriel Krisman Bertazi 	FANOTIFY_INLINE_FH(object_fh, FANOTIFY_INLINE_FH_LEN);
2887088f357SJan Kara };
2897088f357SJan Kara 
2907088f357SJan Kara static inline struct fanotify_fid_event *
FANOTIFY_FE(struct fanotify_event * event)2917088f357SJan Kara FANOTIFY_FE(struct fanotify_event *event)
292e9e0c890SAmir Goldstein {
2937088f357SJan Kara 	return container_of(event, struct fanotify_fid_event, fae);
294e9e0c890SAmir Goldstein }
295e9e0c890SAmir Goldstein 
296cacfb956SAmir Goldstein struct fanotify_name_event {
297cacfb956SAmir Goldstein 	struct fanotify_event fae;
298cacfb956SAmir Goldstein 	__kernel_fsid_t fsid;
299f454fa61SAmir Goldstein 	struct fanotify_info info;
300cacfb956SAmir Goldstein };
301cacfb956SAmir Goldstein 
302cacfb956SAmir Goldstein static inline struct fanotify_name_event *
FANOTIFY_NE(struct fanotify_event * event)303cacfb956SAmir Goldstein FANOTIFY_NE(struct fanotify_event *event)
304cacfb956SAmir Goldstein {
305cacfb956SAmir Goldstein 	return container_of(event, struct fanotify_name_event, fae);
306cacfb956SAmir Goldstein }
307cacfb956SAmir Goldstein 
308734a1a5eSGabriel Krisman Bertazi struct fanotify_error_event {
309734a1a5eSGabriel Krisman Bertazi 	struct fanotify_event fae;
310130a3c74SGabriel Krisman Bertazi 	s32 error; /* Error reported by the Filesystem. */
3118a6ae641SGabriel Krisman Bertazi 	u32 err_count; /* Suppressed errors count */
3128a6ae641SGabriel Krisman Bertazi 
3138a6ae641SGabriel Krisman Bertazi 	__kernel_fsid_t fsid; /* FSID this error refers to. */
314936d6a38SGabriel Krisman Bertazi 
315936d6a38SGabriel Krisman Bertazi 	FANOTIFY_INLINE_FH(object_fh, MAX_HANDLE_SZ);
316734a1a5eSGabriel Krisman Bertazi };
317734a1a5eSGabriel Krisman Bertazi 
318734a1a5eSGabriel Krisman Bertazi static inline struct fanotify_error_event *
FANOTIFY_EE(struct fanotify_event * event)319734a1a5eSGabriel Krisman Bertazi FANOTIFY_EE(struct fanotify_event *event)
320734a1a5eSGabriel Krisman Bertazi {
321734a1a5eSGabriel Krisman Bertazi 	return container_of(event, struct fanotify_error_event, fae);
322734a1a5eSGabriel Krisman Bertazi }
323734a1a5eSGabriel Krisman Bertazi 
fanotify_event_fsid(struct fanotify_event * event)324afc894c7SJan Kara static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event)
325e9e0c890SAmir Goldstein {
3267088f357SJan Kara 	if (event->type == FANOTIFY_EVENT_TYPE_FID)
3277088f357SJan Kara 		return &FANOTIFY_FE(event)->fsid;
328cacfb956SAmir Goldstein 	else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
329cacfb956SAmir Goldstein 		return &FANOTIFY_NE(event)->fsid;
330936d6a38SGabriel Krisman Bertazi 	else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
331936d6a38SGabriel Krisman Bertazi 		return &FANOTIFY_EE(event)->fsid;
332afc894c7SJan Kara 	else
333afc894c7SJan Kara 		return NULL;
334e9e0c890SAmir Goldstein }
335e9e0c890SAmir Goldstein 
fanotify_event_object_fh(struct fanotify_event * event)336afc894c7SJan Kara static inline struct fanotify_fh *fanotify_event_object_fh(
337afc894c7SJan Kara 						struct fanotify_event *event)
3385e469c83SAmir Goldstein {
3397088f357SJan Kara 	if (event->type == FANOTIFY_EVENT_TYPE_FID)
3407088f357SJan Kara 		return &FANOTIFY_FE(event)->object_fh;
3417e8283afSAmir Goldstein 	else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
3427e8283afSAmir Goldstein 		return fanotify_info_file_fh(&FANOTIFY_NE(event)->info);
343936d6a38SGabriel Krisman Bertazi 	else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
344936d6a38SGabriel Krisman Bertazi 		return &FANOTIFY_EE(event)->object_fh;
345afc894c7SJan Kara 	else
346afc894c7SJan Kara 		return NULL;
347afc894c7SJan Kara }
348afc894c7SJan Kara 
fanotify_event_info(struct fanotify_event * event)349f454fa61SAmir Goldstein static inline struct fanotify_info *fanotify_event_info(
350cacfb956SAmir Goldstein 						struct fanotify_event *event)
351cacfb956SAmir Goldstein {
352cacfb956SAmir Goldstein 	if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
353f454fa61SAmir Goldstein 		return &FANOTIFY_NE(event)->info;
354cacfb956SAmir Goldstein 	else
355cacfb956SAmir Goldstein 		return NULL;
356cacfb956SAmir Goldstein }
357cacfb956SAmir Goldstein 
fanotify_event_object_fh_len(struct fanotify_event * event)358afc894c7SJan Kara static inline int fanotify_event_object_fh_len(struct fanotify_event *event)
359afc894c7SJan Kara {
3607e8283afSAmir Goldstein 	struct fanotify_info *info = fanotify_event_info(event);
361afc894c7SJan Kara 	struct fanotify_fh *fh = fanotify_event_object_fh(event);
362afc894c7SJan Kara 
3637e8283afSAmir Goldstein 	if (info)
3647e8283afSAmir Goldstein 		return info->file_fh_totlen ? fh->len : 0;
3657e8283afSAmir Goldstein 	else
366afc894c7SJan Kara 		return fh ? fh->len : 0;
3675e469c83SAmir Goldstein }
3685e469c83SAmir Goldstein 
fanotify_event_dir_fh_len(struct fanotify_event * event)369f454fa61SAmir Goldstein static inline int fanotify_event_dir_fh_len(struct fanotify_event *event)
370cacfb956SAmir Goldstein {
371f454fa61SAmir Goldstein 	struct fanotify_info *info = fanotify_event_info(event);
372cacfb956SAmir Goldstein 
373f454fa61SAmir Goldstein 	return info ? fanotify_info_dir_fh_len(info) : 0;
374cacfb956SAmir Goldstein }
375cacfb956SAmir Goldstein 
fanotify_event_dir2_fh_len(struct fanotify_event * event)3767326e382SAmir Goldstein static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event)
3777326e382SAmir Goldstein {
3787326e382SAmir Goldstein 	struct fanotify_info *info = fanotify_event_info(event);
3797326e382SAmir Goldstein 
3807326e382SAmir Goldstein 	return info ? fanotify_info_dir2_fh_len(info) : 0;
3817326e382SAmir Goldstein }
3827326e382SAmir Goldstein 
fanotify_event_has_object_fh(struct fanotify_event * event)3834bd5a5c8SGabriel Krisman Bertazi static inline bool fanotify_event_has_object_fh(struct fanotify_event *event)
3844bd5a5c8SGabriel Krisman Bertazi {
385936d6a38SGabriel Krisman Bertazi 	/* For error events, even zeroed fh are reported. */
386936d6a38SGabriel Krisman Bertazi 	if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR)
387936d6a38SGabriel Krisman Bertazi 		return true;
3884bd5a5c8SGabriel Krisman Bertazi 	return fanotify_event_object_fh_len(event) > 0;
3894bd5a5c8SGabriel Krisman Bertazi }
3904bd5a5c8SGabriel Krisman Bertazi 
fanotify_event_has_dir_fh(struct fanotify_event * event)3914bd5a5c8SGabriel Krisman Bertazi static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event)
3924bd5a5c8SGabriel Krisman Bertazi {
3934bd5a5c8SGabriel Krisman Bertazi 	return fanotify_event_dir_fh_len(event) > 0;
3944bd5a5c8SGabriel Krisman Bertazi }
3954bd5a5c8SGabriel Krisman Bertazi 
fanotify_event_has_dir2_fh(struct fanotify_event * event)3967326e382SAmir Goldstein static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event)
3977326e382SAmir Goldstein {
3987326e382SAmir Goldstein 	return fanotify_event_dir2_fh_len(event) > 0;
3997326e382SAmir Goldstein }
4007326e382SAmir Goldstein 
fanotify_event_has_any_dir_fh(struct fanotify_event * event)4017326e382SAmir Goldstein static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event)
4027326e382SAmir Goldstein {
4037326e382SAmir Goldstein 	return fanotify_event_has_dir_fh(event) ||
4047326e382SAmir Goldstein 		fanotify_event_has_dir2_fh(event);
4057326e382SAmir Goldstein }
4067326e382SAmir Goldstein 
4077088f357SJan Kara struct fanotify_path_event {
4087088f357SJan Kara 	struct fanotify_event fae;
4097088f357SJan Kara 	struct path path;
4107088f357SJan Kara };
4117088f357SJan Kara 
4127088f357SJan Kara static inline struct fanotify_path_event *
FANOTIFY_PE(struct fanotify_event * event)4137088f357SJan Kara FANOTIFY_PE(struct fanotify_event *event)
4147088f357SJan Kara {
4157088f357SJan Kara 	return container_of(event, struct fanotify_path_event, fae);
4167088f357SJan Kara }
4177088f357SJan Kara 
418f083441bSJan Kara /*
419f083441bSJan Kara  * Structure for permission fanotify events. It gets allocated and freed in
420f083441bSJan Kara  * fanotify_handle_event() since we wait there for user response. When the
421f083441bSJan Kara  * information is retrieved by userspace the structure is moved from
422f083441bSJan Kara  * group->notification_list to group->fanotify_data.access_list to wait for
423f083441bSJan Kara  * user response.
424f083441bSJan Kara  */
42533913997SAmir Goldstein struct fanotify_perm_event {
42633913997SAmir Goldstein 	struct fanotify_event fae;
4277088f357SJan Kara 	struct path path;
4282e0a5471SRichard Guy Briggs 	u32 response;			/* userspace answer to the event */
42940873284SJan Kara 	unsigned short state;		/* state of the event */
430f083441bSJan Kara 	int fd;		/* fd we passed to userspace for this event */
431*70529a19SRichard Guy Briggs 	union {
432*70529a19SRichard Guy Briggs 		struct fanotify_response_info_header hdr;
433*70529a19SRichard Guy Briggs 		struct fanotify_response_info_audit_rule audit_rule;
434*70529a19SRichard Guy Briggs 	};
435f083441bSJan Kara };
436f083441bSJan Kara 
43733913997SAmir Goldstein static inline struct fanotify_perm_event *
FANOTIFY_PERM(struct fanotify_event * event)4387088f357SJan Kara FANOTIFY_PERM(struct fanotify_event *event)
439f083441bSJan Kara {
4407088f357SJan Kara 	return container_of(event, struct fanotify_perm_event, fae);
441f083441bSJan Kara }
4426685df31SMiklos Szeredi 
fanotify_is_perm_event(u32 mask)4436685df31SMiklos Szeredi static inline bool fanotify_is_perm_event(u32 mask)
4446685df31SMiklos Szeredi {
4456685df31SMiklos Szeredi 	return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) &&
44623c9deebSAmir Goldstein 		mask & FANOTIFY_PERM_EVENTS;
4476685df31SMiklos Szeredi }
448f083441bSJan Kara 
FANOTIFY_E(struct fsnotify_event * fse)44933913997SAmir Goldstein static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
4507053aee2SJan Kara {
45133913997SAmir Goldstein 	return container_of(fse, struct fanotify_event, fse);
4527053aee2SJan Kara }
453f083441bSJan Kara 
fanotify_is_error_event(u32 mask)45483e9acbeSGabriel Krisman Bertazi static inline bool fanotify_is_error_event(u32 mask)
45583e9acbeSGabriel Krisman Bertazi {
45683e9acbeSGabriel Krisman Bertazi 	return mask & FAN_FS_ERROR;
45783e9acbeSGabriel Krisman Bertazi }
45883e9acbeSGabriel Krisman Bertazi 
fanotify_event_path(struct fanotify_event * event)459d5bf8889SAl Viro static inline const struct path *fanotify_event_path(struct fanotify_event *event)
460afc894c7SJan Kara {
4617088f357SJan Kara 	if (event->type == FANOTIFY_EVENT_TYPE_PATH)
4627088f357SJan Kara 		return &FANOTIFY_PE(event)->path;
4637088f357SJan Kara 	else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM)
4647088f357SJan Kara 		return &FANOTIFY_PERM(event)->path;
465afc894c7SJan Kara 	else
466afc894c7SJan Kara 		return NULL;
467afc894c7SJan Kara }
46894e00d28SAmir Goldstein 
46994e00d28SAmir Goldstein /*
47094e00d28SAmir Goldstein  * Use 128 size hash table to speed up events merge.
47194e00d28SAmir Goldstein  */
47294e00d28SAmir Goldstein #define FANOTIFY_HTABLE_BITS	(7)
47394e00d28SAmir Goldstein #define FANOTIFY_HTABLE_SIZE	(1 << FANOTIFY_HTABLE_BITS)
47494e00d28SAmir Goldstein #define FANOTIFY_HTABLE_MASK	(FANOTIFY_HTABLE_SIZE - 1)
47594e00d28SAmir Goldstein 
47694e00d28SAmir Goldstein /*
47794e00d28SAmir Goldstein  * Permission events and overflow event do not get merged - don't hash them.
47894e00d28SAmir Goldstein  */
fanotify_is_hashed_event(u32 mask)47994e00d28SAmir Goldstein static inline bool fanotify_is_hashed_event(u32 mask)
48094e00d28SAmir Goldstein {
481808967a0SGabriel Krisman Bertazi 	return !(fanotify_is_perm_event(mask) ||
482808967a0SGabriel Krisman Bertazi 		 fsnotify_is_overflow_event(mask));
48394e00d28SAmir Goldstein }
48494e00d28SAmir Goldstein 
fanotify_event_hash_bucket(struct fsnotify_group * group,struct fanotify_event * event)48594e00d28SAmir Goldstein static inline unsigned int fanotify_event_hash_bucket(
48694e00d28SAmir Goldstein 						struct fsnotify_group *group,
48794e00d28SAmir Goldstein 						struct fanotify_event *event)
48894e00d28SAmir Goldstein {
48994e00d28SAmir Goldstein 	return event->hash & FANOTIFY_HTABLE_MASK;
49094e00d28SAmir Goldstein }
4914adce25cSAmir Goldstein 
fanotify_mark_user_flags(struct fsnotify_mark * mark)4924adce25cSAmir Goldstein static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
4934adce25cSAmir Goldstein {
4944adce25cSAmir Goldstein 	unsigned int mflags = 0;
4954adce25cSAmir Goldstein 
4964adce25cSAmir Goldstein 	if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
4974adce25cSAmir Goldstein 		mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
4987d5e005dSAmir Goldstein 	if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)
4997d5e005dSAmir Goldstein 		mflags |= FAN_MARK_EVICTABLE;
500e252f2edSAmir Goldstein 	if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
501e252f2edSAmir Goldstein 		mflags |= FAN_MARK_IGNORE;
5024adce25cSAmir Goldstein 
5034adce25cSAmir Goldstein 	return mflags;
5044adce25cSAmir Goldstein }
505