Skip to content

Commit

Permalink
Merge tag 'fsnotify_for_v5.7-rc1' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/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
  • Loading branch information
Linus Torvalds committed Apr 6, 2020
2 parents 74e934b + 6def1a1 commit b6ff107
Showing 12 changed files with 637 additions and 363 deletions.
302 changes: 228 additions & 74 deletions fs/notify/fanotify/fanotify.c

Large diffs are not rendered by default.

189 changes: 127 additions & 62 deletions fs/notify/fanotify/fanotify.h
Original file line number Diff line number Diff line change
@@ -5,7 +5,8 @@
#include <linux/exportfs.h>

extern struct kmem_cache *fanotify_mark_cache;
extern struct kmem_cache *fanotify_event_cachep;
extern struct kmem_cache *fanotify_fid_event_cachep;
extern struct kmem_cache *fanotify_path_event_cachep;
extern struct kmem_cache *fanotify_perm_event_cachep;

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

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

struct fanotify_fid {
__kernel_fsid_t fsid;
union {
unsigned char fh[FANOTIFY_INLINE_FH_LEN];
unsigned char *ext_fh;
};
};
struct fanotify_fh {
unsigned char buf[FANOTIFY_INLINE_FH_LEN];
u8 type;
u8 len;
} __aligned(4);

static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh)
{
return fh->len > FANOTIFY_INLINE_FH_LEN;
}

static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh)
{
BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) >
FANOTIFY_INLINE_FH_LEN);
return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *));
}

static inline void *fanotify_fid_fh(struct fanotify_fid *fid,
unsigned int fh_len)
static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh)
{
return fh_len <= FANOTIFY_INLINE_FH_LEN ? fid->fh : fid->ext_fh;
return *fanotify_fh_ext_buf_ptr(fh);
}

static inline bool fanotify_fid_equal(struct fanotify_fid *fid1,
struct fanotify_fid *fid2,
unsigned int fh_len)
static inline void *fanotify_fh_buf(struct fanotify_fh *fh)
{
return fid1->fsid.val[0] == fid2->fsid.val[0] &&
fid1->fsid.val[1] == fid2->fsid.val[1] &&
!memcmp(fanotify_fid_fh(fid1, fh_len),
fanotify_fid_fh(fid2, fh_len), fh_len);
return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf;
}

/*
* Structure for normal fanotify events. It gets allocated in
* Common structure for fanotify events. Concrete structs are allocated in
* fanotify_handle_event() and freed when the information is retrieved by
* userspace
* userspace. The type of event determines how it was allocated, how it will
* be freed and which concrete struct it may be cast to.
*/
enum fanotify_event_type {
FANOTIFY_EVENT_TYPE_FID, /* fixed length */
FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */
FANOTIFY_EVENT_TYPE_PATH,
FANOTIFY_EVENT_TYPE_PATH_PERM,
};

struct fanotify_event {
struct fsnotify_event fse;
u32 mask;
/*
* Those fields are outside fanotify_fid to pack fanotify_event nicely
* on 64bit arch and to use fh_type as an indication of whether path
* or fid are used in the union:
* FILEID_ROOT (0) for path, > 0 for fid, FILEID_INVALID for neither.
*/
u8 fh_type;
u8 fh_len;
u16 pad;
union {
/*
* We hold ref to this path so it may be dereferenced at any
* point during this object's lifetime
*/
struct path path;
/*
* With FAN_REPORT_FID, we do not hold any reference on the
* victim object. Instead we store its NFS file handle and its
* filesystem's fsid as a unique identifier.
*/
struct fanotify_fid fid;
};
enum fanotify_event_type type;
struct pid *pid;
};

static inline bool fanotify_event_has_path(struct fanotify_event *event)
struct fanotify_fid_event {
struct fanotify_event fae;
__kernel_fsid_t fsid;
struct fanotify_fh object_fh;
};

static inline struct fanotify_fid_event *
FANOTIFY_FE(struct fanotify_event *event)
{
return event->fh_type == FILEID_ROOT;
return container_of(event, struct fanotify_fid_event, fae);
}

static inline bool fanotify_event_has_fid(struct fanotify_event *event)
struct fanotify_name_event {
struct fanotify_event fae;
__kernel_fsid_t fsid;
struct fanotify_fh dir_fh;
u8 name_len;
char name[0];
};

static inline struct fanotify_name_event *
FANOTIFY_NE(struct fanotify_event *event)
{
return event->fh_type != FILEID_ROOT &&
event->fh_type != FILEID_INVALID;
return container_of(event, struct fanotify_name_event, fae);
}

static inline bool fanotify_event_has_ext_fh(struct fanotify_event *event)
static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event)
{
return fanotify_event_has_fid(event) &&
event->fh_len > FANOTIFY_INLINE_FH_LEN;
if (event->type == FANOTIFY_EVENT_TYPE_FID)
return &FANOTIFY_FE(event)->fsid;
else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
return &FANOTIFY_NE(event)->fsid;
else
return NULL;
}

static inline void *fanotify_event_fh(struct fanotify_event *event)
static inline struct fanotify_fh *fanotify_event_object_fh(
struct fanotify_event *event)
{
return fanotify_fid_fh(&event->fid, event->fh_len);
if (event->type == FANOTIFY_EVENT_TYPE_FID)
return &FANOTIFY_FE(event)->object_fh;
else
return NULL;
}

static inline struct fanotify_fh *fanotify_event_dir_fh(
struct fanotify_event *event)
{
if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME)
return &FANOTIFY_NE(event)->dir_fh;
else
return NULL;
}

static inline int fanotify_event_object_fh_len(struct fanotify_event *event)
{
struct fanotify_fh *fh = fanotify_event_object_fh(event);

return fh ? fh->len : 0;
}

static inline bool fanotify_event_has_name(struct fanotify_event *event)
{
return event->type == FANOTIFY_EVENT_TYPE_FID_NAME;
}

static inline int fanotify_event_name_len(struct fanotify_event *event)
{
return fanotify_event_has_name(event) ?
FANOTIFY_NE(event)->name_len : 0;
}

struct fanotify_path_event {
struct fanotify_event fae;
struct path path;
};

static inline struct fanotify_path_event *
FANOTIFY_PE(struct fanotify_event *event)
{
return container_of(event, struct fanotify_path_event, fae);
}

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

static inline struct fanotify_perm_event *
FANOTIFY_PE(struct fsnotify_event *fse)
FANOTIFY_PERM(struct fanotify_event *event)
{
return container_of(fse, struct fanotify_perm_event, fae.fse);
return container_of(event, struct fanotify_perm_event, fae);
}

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

static inline bool fanotify_event_has_path(struct fanotify_event *event)
{
return event->type == FANOTIFY_EVENT_TYPE_PATH ||
event->type == FANOTIFY_EVENT_TYPE_PATH_PERM;
}

static inline struct path *fanotify_event_path(struct fanotify_event *event)
{
if (event->type == FANOTIFY_EVENT_TYPE_PATH)
return &FANOTIFY_PE(event)->path;
else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM)
return &FANOTIFY_PERM(event)->path;
else
return NULL;
}

struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
struct inode *inode, u32 mask,
const void *data, int data_type,
const struct qstr *file_name,
__kernel_fsid_t *fsid);
Loading

0 comments on commit b6ff107

Please sign in to comment.