Skip to content

Commit b6ff107

Browse files
committed
Merge tag 'fsnotify_for_v5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: "This implements the fanotify FAN_DIR_MODIFY event. This event reports the name in a directory under which a change happened and together with the directory filehandle and fstatat() allows reliable and efficient implementation of directory synchronization" * tag 'fsnotify_for_v5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fanotify: Fix the checks in fanotify_fsid_equal fanotify: report name info for FAN_DIR_MODIFY event fanotify: record name info for FAN_DIR_MODIFY event fanotify: Drop fanotify_event_has_fid() fanotify: prepare to report both parent and child fid's fanotify: send FAN_DIR_MODIFY event flavor with dir inode and name fanotify: divorce fanotify_path_event and fanotify_fid_event fanotify: Store fanotify handles differently fanotify: Simplify create_fd() fanotify: fix merging marks masks with FAN_ONDIR fanotify: merge duplicate events on parent and child fsnotify: replace inode pointer with an object id fsnotify: simplify arguments passing to fsnotify_parent() fsnotify: use helpers to access data by data_type fsnotify: funnel all dirent events through fsnotify_name() fsnotify: factor helpers fsnotify_dentry() and fsnotify_file() fsnotify: tidy up FS_ and FAN_ constants
2 parents 74e934b + 6def1a1 commit b6ff107

File tree

12 files changed

+637
-363
lines changed

12 files changed

+637
-363
lines changed

fs/notify/fanotify/fanotify.c

Lines changed: 228 additions & 74 deletions
Large diffs are not rendered by default.

fs/notify/fanotify/fanotify.h

Lines changed: 127 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
#include <linux/exportfs.h>
66

77
extern struct kmem_cache *fanotify_mark_cache;
8-
extern struct kmem_cache *fanotify_event_cachep;
8+
extern struct kmem_cache *fanotify_fid_event_cachep;
9+
extern struct kmem_cache *fanotify_path_event_cachep;
910
extern struct kmem_cache *fanotify_perm_event_cachep;
1011

1112
/* Possible states of the permission event */
@@ -18,94 +19,140 @@ enum {
1819

1920
/*
2021
* 3 dwords are sufficient for most local fs (64bit ino, 32bit generation).
21-
* For 32bit arch, fid increases the size of fanotify_event by 12 bytes and
22-
* fh_* fields increase the size of fanotify_event by another 4 bytes.
23-
* For 64bit arch, fid increases the size of fanotify_fid by 8 bytes and
24-
* fh_* fields are packed in a hole after mask.
22+
* fh buf should be dword aligned. On 64bit arch, the ext_buf pointer is
23+
* stored in either the first or last 2 dwords.
2524
*/
26-
#if BITS_PER_LONG == 32
2725
#define FANOTIFY_INLINE_FH_LEN (3 << 2)
28-
#else
29-
#define FANOTIFY_INLINE_FH_LEN (4 << 2)
30-
#endif
3126

32-
struct fanotify_fid {
33-
__kernel_fsid_t fsid;
34-
union {
35-
unsigned char fh[FANOTIFY_INLINE_FH_LEN];
36-
unsigned char *ext_fh;
37-
};
38-
};
27+
struct fanotify_fh {
28+
unsigned char buf[FANOTIFY_INLINE_FH_LEN];
29+
u8 type;
30+
u8 len;
31+
} __aligned(4);
32+
33+
static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh)
34+
{
35+
return fh->len > FANOTIFY_INLINE_FH_LEN;
36+
}
37+
38+
static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh)
39+
{
40+
BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) >
41+
FANOTIFY_INLINE_FH_LEN);
42+
return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *));
43+
}
3944

40-
static inline void *fanotify_fid_fh(struct fanotify_fid *fid,
41-
unsigned int fh_len)
45+
static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh)
4246
{
43-
return fh_len <= FANOTIFY_INLINE_FH_LEN ? fid->fh : fid->ext_fh;
47+
return *fanotify_fh_ext_buf_ptr(fh);
4448
}
4549

46-
static inline bool fanotify_fid_equal(struct fanotify_fid *fid1,
47-
struct fanotify_fid *fid2,
48-
unsigned int fh_len)
50+
static inline void *fanotify_fh_buf(struct fanotify_fh *fh)
4951
{
50-
return fid1->fsid.val[0] == fid2->fsid.val[0] &&
51-
fid1->fsid.val[1] == fid2->fsid.val[1] &&
52-
!memcmp(fanotify_fid_fh(fid1, fh_len),
53-
fanotify_fid_fh(fid2, fh_len), fh_len);
52+
return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf;
5453
}
5554

5655
/*
57-
* Structure for normal fanotify events. It gets allocated in
56+
* Common structure for fanotify events. Concrete structs are allocated in
5857
* fanotify_handle_event() and freed when the information is retrieved by
59-
* userspace
58+
* userspace. The type of event determines how it was allocated, how it will
59+
* be freed and which concrete struct it may be cast to.
6060
*/
61+
enum fanotify_event_type {
62+
FANOTIFY_EVENT_TYPE_FID, /* fixed length */
63+
FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */
64+
FANOTIFY_EVENT_TYPE_PATH,
65+
FANOTIFY_EVENT_TYPE_PATH_PERM,
66+
};
67+
6168
struct fanotify_event {
6269
struct fsnotify_event fse;
6370
u32 mask;
64-
/*
65-
* Those fields are outside fanotify_fid to pack fanotify_event nicely
66-
* on 64bit arch and to use fh_type as an indication of whether path
67-
* or fid are used in the union:
68-
* FILEID_ROOT (0) for path, > 0 for fid, FILEID_INVALID for neither.
69-
*/
70-
u8 fh_type;
71-
u8 fh_len;
72-
u16 pad;
73-
union {
74-
/*
75-
* We hold ref to this path so it may be dereferenced at any
76-
* point during this object's lifetime
77-
*/
78-
struct path path;
79-
/*
80-
* With FAN_REPORT_FID, we do not hold any reference on the
81-
* victim object. Instead we store its NFS file handle and its
82-
* filesystem's fsid as a unique identifier.
83-
*/
84-
struct fanotify_fid fid;
85-
};
71+
enum fanotify_event_type type;
8672
struct pid *pid;
8773
};
8874

89-
static inline bool fanotify_event_has_path(struct fanotify_event *event)
75+
struct fanotify_fid_event {
76+
struct fanotify_event fae;
77+
__kernel_fsid_t fsid;
78+
struct fanotify_fh object_fh;
79+
};
80+
81+
static inline struct fanotify_fid_event *
82+
FANOTIFY_FE(struct fanotify_event *event)
9083
{
91-
return event->fh_type == FILEID_ROOT;
84+
return container_of(event, struct fanotify_fid_event, fae);
9285
}
9386

94-
static inline bool fanotify_event_has_fid(struct fanotify_event *event)
87+
struct fanotify_name_event {
88+
struct fanotify_event fae;
89+
__kernel_fsid_t fsid;
90+
struct fanotify_fh dir_fh;
91+
u8 name_len;
92+
char name[0];
93+
};
94+
95+
static inline struct fanotify_name_event *
96+
FANOTIFY_NE(struct fanotify_event *event)
9597
{
96-
return event->fh_type != FILEID_ROOT &&
97-
event->fh_type != FILEID_INVALID;
98+
return container_of(event, struct fanotify_name_event, fae);
9899
}
99100

100-
static inline bool fanotify_event_has_ext_fh(struct fanotify_event *event)
101+
static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event)
101102
{
102-
return fanotify_event_has_fid(event) &&
103-
event->fh_len > FANOTIFY_INLINE_FH_LEN;
103+
if (event->type == FANOTIFY_EVENT_TYPE_FID)
104+
return &FANOTIFY_FE(event)->fsid;
105+
else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
106+
return &FANOTIFY_NE(event)->fsid;
107+
else
108+
return NULL;
104109
}
105110

106-
static inline void *fanotify_event_fh(struct fanotify_event *event)
111+
static inline struct fanotify_fh *fanotify_event_object_fh(
112+
struct fanotify_event *event)
107113
{
108-
return fanotify_fid_fh(&event->fid, event->fh_len);
114+
if (event->type == FANOTIFY_EVENT_TYPE_FID)
115+
return &FANOTIFY_FE(event)->object_fh;
116+
else
117+
return NULL;
118+
}
119+
120+
static inline struct fanotify_fh *fanotify_event_dir_fh(
121+
struct fanotify_event *event)
122+
{
123+
if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
124+
return &FANOTIFY_NE(event)->dir_fh;
125+
else
126+
return NULL;
127+
}
128+
129+
static inline int fanotify_event_object_fh_len(struct fanotify_event *event)
130+
{
131+
struct fanotify_fh *fh = fanotify_event_object_fh(event);
132+
133+
return fh ? fh->len : 0;
134+
}
135+
136+
static inline bool fanotify_event_has_name(struct fanotify_event *event)
137+
{
138+
return event->type == FANOTIFY_EVENT_TYPE_FID_NAME;
139+
}
140+
141+
static inline int fanotify_event_name_len(struct fanotify_event *event)
142+
{
143+
return fanotify_event_has_name(event) ?
144+
FANOTIFY_NE(event)->name_len : 0;
145+
}
146+
147+
struct fanotify_path_event {
148+
struct fanotify_event fae;
149+
struct path path;
150+
};
151+
152+
static inline struct fanotify_path_event *
153+
FANOTIFY_PE(struct fanotify_event *event)
154+
{
155+
return container_of(event, struct fanotify_path_event, fae);
109156
}
110157

111158
/*
@@ -117,15 +164,16 @@ static inline void *fanotify_event_fh(struct fanotify_event *event)
117164
*/
118165
struct fanotify_perm_event {
119166
struct fanotify_event fae;
167+
struct path path;
120168
unsigned short response; /* userspace answer to the event */
121169
unsigned short state; /* state of the event */
122170
int fd; /* fd we passed to userspace for this event */
123171
};
124172

125173
static inline struct fanotify_perm_event *
126-
FANOTIFY_PE(struct fsnotify_event *fse)
174+
FANOTIFY_PERM(struct fanotify_event *event)
127175
{
128-
return container_of(fse, struct fanotify_perm_event, fae.fse);
176+
return container_of(event, struct fanotify_perm_event, fae);
129177
}
130178

131179
static inline bool fanotify_is_perm_event(u32 mask)
@@ -139,7 +187,24 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
139187
return container_of(fse, struct fanotify_event, fse);
140188
}
141189

190+
static inline bool fanotify_event_has_path(struct fanotify_event *event)
191+
{
192+
return event->type == FANOTIFY_EVENT_TYPE_PATH ||
193+
event->type == FANOTIFY_EVENT_TYPE_PATH_PERM;
194+
}
195+
196+
static inline struct path *fanotify_event_path(struct fanotify_event *event)
197+
{
198+
if (event->type == FANOTIFY_EVENT_TYPE_PATH)
199+
return &FANOTIFY_PE(event)->path;
200+
else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM)
201+
return &FANOTIFY_PERM(event)->path;
202+
else
203+
return NULL;
204+
}
205+
142206
struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
143207
struct inode *inode, u32 mask,
144208
const void *data, int data_type,
209+
const struct qstr *file_name,
145210
__kernel_fsid_t *fsid);

0 commit comments

Comments
 (0)