vfs-7.2-rc1.directory.delegations

Please consider pulling these changes from the signed vfs-7.2-rc1.directory.delegations tag.
 
 Thanks!
 Christian
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCaiwLKQAKCRCRxhvAZXjc
 opMRAQD9zbiUu66CHNd49yD3sFtuG8uM7I2VuIoczgW+qKka5QEA8HBVqMtdurZf
 eEcj415FqHQNX1W3jytjU1jYjiwmtgY=
 =Ahl/
 -----END PGP SIGNATURE-----

Merge tag 'vfs-7.2-rc1.directory.delegations' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs directory delegations from Christian Brauner:
 "This contains the VFS prerequisites for supporting directory
  delegations in nfsd via CB_NOTIFY callbacks.

  The filelock core gains support for ignoring delegation breaks for
  directory change events together with an inode_lease_ignore_mask()
  helper, and fsnotify gains fsnotify_modify_mark_mask() and a
  FSNOTIFY_EVENT_RENAME data type.

  With this in place nfsd can request delegations on directories and set
  up inotify watches to trigger sending CB_NOTIFY events to clients
  instead of having every directory change break the delegation.

  New tracepoints are added to fsnotify() and to the start of
  break_lease(), and trace_break_lease_block() is passed the currently
  blocking lease instead of the new one.

  A follow-up fix moves the LEASE_BREAK_* flags out of
  #ifdef CONFIG_FILE_LOCKING to fix the build for CONFIG_FILE_LOCKING=n
  configurations"

* tag 'vfs-7.2-rc1.directory.delegations' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  filelock: move LEASE_BREAK_* flags out of #ifdef CONFIG_FILE_LOCKING
  fsnotify: add FSNOTIFY_EVENT_RENAME data type
  fsnotify: add fsnotify_modify_mark_mask()
  fsnotify: new tracepoint in fsnotify()
  filelock: add an inode_lease_ignore_mask helper
  filelock: add a tracepoint to start of break_lease()
  filelock: add support for ignoring deleg breaks for dir change events
  filelock: pass current blocking lease to trace_break_lease_block() rather than "new_fl"
This commit is contained in:
Linus Torvalds 2026-06-15 02:50:44 +05:30
commit 6b5b72ac2c
13 changed files with 341 additions and 71 deletions

View File

@ -547,7 +547,7 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
* breaking the delegation in this case.
*/
if (!(ia_valid & ATTR_DELEG)) {
error = try_break_deleg(inode, delegated_inode);
error = try_break_deleg(inode, 0, delegated_inode);
if (error)
return error;
}

View File

@ -1582,30 +1582,96 @@ static bool leases_conflict(struct file_lock_core *lc, struct file_lock_core *bc
return rc;
}
static bool
any_leases_conflict(struct inode *inode, struct file_lease *breaker)
#define IGNORE_MASK (FL_IGN_DIR_CREATE | FL_IGN_DIR_DELETE | FL_IGN_DIR_RENAME)
/**
* inode_lease_ignore_mask - return union of all ignored inode events for this inode
* @inode: inode of which to get ignore mask
*
* Walk the list of leases, and return the result of all of
* their FL_IGN_DIR_* bits or'ed together.
*/
u32
inode_lease_ignore_mask(struct inode *inode)
{
struct file_lock_context *ctx = inode->i_flctx;
struct file_lock_context *ctx;
struct file_lock_core *flc;
u32 mask = 0;
lockdep_assert_held(&ctx->flc_lock);
ctx = locks_inode_context(inode);
if (!ctx)
return 0;
spin_lock(&ctx->flc_lock);
list_for_each_entry(flc, &ctx->flc_lease, flc_list) {
if (leases_conflict(flc, &breaker->c))
return true;
mask |= flc->flc_flags & IGNORE_MASK;
/* If we already have everything, we can stop */
if (mask == IGNORE_MASK)
break;
}
spin_unlock(&ctx->flc_lock);
return mask;
}
EXPORT_SYMBOL_GPL(inode_lease_ignore_mask);
static bool
ignore_dir_deleg_break(struct file_lease *fl, unsigned int flags)
{
if ((flags & LEASE_BREAK_DIR_CREATE) && (fl->c.flc_flags & FL_IGN_DIR_CREATE))
return true;
if ((flags & LEASE_BREAK_DIR_DELETE) && (fl->c.flc_flags & FL_IGN_DIR_DELETE))
return true;
if ((flags & LEASE_BREAK_DIR_RENAME) && (fl->c.flc_flags & FL_IGN_DIR_RENAME))
return true;
return false;
}
static unsigned int
break_lease_flags_to_type(unsigned int flags)
{
if (flags & LEASE_BREAK_LEASE)
return FL_LEASE;
else if (flags & LEASE_BREAK_DELEG)
return FL_DELEG;
else if (flags & LEASE_BREAK_LAYOUT)
return FL_LAYOUT;
else
return 0;
}
static struct file_lease *
first_visible_lease(struct inode *inode, struct file_lease *new_fl, unsigned int flags)
{
struct file_lock_context *ctx = locks_inode_context(inode);
struct file_lease *fl;
lockdep_assert_held(&ctx->flc_lock);
list_for_each_entry(fl, &ctx->flc_lease, c.flc_list) {
if (!leases_conflict(&fl->c, &new_fl->c))
continue;
if (S_ISDIR(inode->i_mode) && ignore_dir_deleg_break(fl, flags))
continue;
return fl;
}
return NULL;
}
/**
* __break_lease - revoke all outstanding leases on file
* @inode: the inode of the file to return
* @flags: LEASE_BREAK_* flags
* __break_lease - revoke all outstanding leases on file
* @inode: the inode of the file to return
* @flags: LEASE_BREAK_* flags
*
* break_lease (inlined for speed) has checked there already is at least
* some kind of lock (maybe a lease) on this file. Leases are broken on
* a call to open() or truncate(). This function can block waiting for the
* lease break unless you specify LEASE_BREAK_NONBLOCK.
* break_lease (inlined for speed) has checked there already is at least
* some kind of lock (maybe a lease) on this file. Leases and Delegations
* are broken on a call to open() or truncate(). Delegations are also
* broken on any event that would change the ctime. Directory delegations
* are broken whenever the directory changes (unless the delegation is set
* up to ignore the event). This function can block waiting for the lease
* break unless you specify LEASE_BREAK_NONBLOCK.
*/
int __break_lease(struct inode *inode, unsigned int flags)
{
@ -1617,13 +1683,10 @@ int __break_lease(struct inode *inode, unsigned int flags)
bool want_write = !(flags & LEASE_BREAK_OPEN_RDONLY);
int error = 0;
if (flags & LEASE_BREAK_LEASE)
type = FL_LEASE;
else if (flags & LEASE_BREAK_DELEG)
type = FL_DELEG;
else if (flags & LEASE_BREAK_LAYOUT)
type = FL_LAYOUT;
else
trace_break_lease(inode, flags);
type = break_lease_flags_to_type(flags);
if (!type)
return -EINVAL;
new_fl = lease_alloc(NULL, type, want_write ? F_WRLCK : F_RDLCK);
@ -1642,7 +1705,7 @@ int __break_lease(struct inode *inode, unsigned int flags)
time_out_leases(inode, &dispose);
if (!any_leases_conflict(inode, new_fl))
if (!first_visible_lease(inode, new_fl, flags))
goto out;
break_time = 0;
@ -1655,6 +1718,8 @@ int __break_lease(struct inode *inode, unsigned int flags)
list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, c.flc_list) {
if (!leases_conflict(&fl->c, &new_fl->c))
continue;
if (S_ISDIR(inode->i_mode) && ignore_dir_deleg_break(fl, flags))
continue;
if (want_write) {
if (fl->c.flc_flags & FL_UNLOCK_PENDING)
continue;
@ -1670,7 +1735,8 @@ int __break_lease(struct inode *inode, unsigned int flags)
locks_delete_lock_ctx(&fl->c, &dispose);
}
if (list_empty(&ctx->flc_lease))
fl = first_visible_lease(inode, new_fl, flags);
if (!fl)
goto out;
if (flags & LEASE_BREAK_NONBLOCK) {
@ -1680,7 +1746,6 @@ int __break_lease(struct inode *inode, unsigned int flags)
}
restart:
fl = list_first_entry(&ctx->flc_lease, struct file_lease, c.flc_list);
break_time = fl->fl_break_time;
if (break_time != 0) {
if (time_after(jiffies, break_time)) {
@ -1691,7 +1756,7 @@ int __break_lease(struct inode *inode, unsigned int flags)
} else
break_time++;
locks_insert_block(&fl->c, &new_fl->c, leases_conflict);
trace_break_lease_block(inode, new_fl);
trace_break_lease_block(inode, fl);
spin_unlock(&ctx->flc_lock);
percpu_up_read(&file_rwsem);
@ -1702,7 +1767,7 @@ int __break_lease(struct inode *inode, unsigned int flags)
percpu_down_read(&file_rwsem);
spin_lock(&ctx->flc_lock);
trace_break_lease_unblock(inode, new_fl);
trace_break_lease_unblock(inode, NULL);
__locks_delete_block(&new_fl->c);
if (error >= 0) {
/*
@ -1711,7 +1776,8 @@ int __break_lease(struct inode *inode, unsigned int flags)
*/
if (error == 0)
time_out_leases(inode, &dispose);
if (any_leases_conflict(inode, new_fl))
fl = first_visible_lease(inode, new_fl, flags);
if (fl)
goto restart;
error = 0;
}

View File

@ -4198,7 +4198,7 @@ int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode,
error = security_inode_create(dir, dentry, mode);
if (error)
return error;
error = try_break_deleg(dir, di);
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, di);
if (error)
return error;
error = dir->i_op->create(idmap, dir, dentry, mode, true);
@ -4497,7 +4497,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
/* Negative dentry, just create the file */
if (!dentry->d_inode && (open_flag & O_CREAT)) {
/* but break the directory lease first! */
error = try_break_deleg(dir_inode, delegated_inode);
error = try_break_deleg(dir_inode, LEASE_BREAK_DIR_CREATE, delegated_inode);
if (error)
goto out_dput;
@ -5123,7 +5123,7 @@ int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
if (error)
return error;
error = try_break_deleg(dir, delegated_inode);
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, delegated_inode);
if (error)
return error;
@ -5264,7 +5264,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
if (max_links && dir->i_nlink >= max_links)
goto err;
error = try_break_deleg(dir, delegated_inode);
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, delegated_inode);
if (error)
goto err;
@ -5369,7 +5369,7 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
if (error)
goto out;
error = try_break_deleg(dir, delegated_inode);
error = try_break_deleg(dir, LEASE_BREAK_DIR_DELETE, delegated_inode);
if (error)
goto out;
@ -5499,10 +5499,10 @@ int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
else {
error = security_inode_unlink(dir, dentry);
if (!error) {
error = try_break_deleg(dir, delegated_inode);
error = try_break_deleg(dir, LEASE_BREAK_DIR_DELETE, delegated_inode);
if (error)
goto out;
error = try_break_deleg(target, delegated_inode);
error = try_break_deleg(target, 0, delegated_inode);
if (error)
goto out;
error = dir->i_op->unlink(dir, dentry);
@ -5646,7 +5646,7 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
if (error)
return error;
error = try_break_deleg(dir, delegated_inode);
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, delegated_inode);
if (error)
return error;
@ -5777,9 +5777,9 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
else if (max_links && inode->i_nlink >= max_links)
error = -EMLINK;
else {
error = try_break_deleg(dir, delegated_inode);
error = try_break_deleg(dir, LEASE_BREAK_DIR_CREATE, delegated_inode);
if (!error)
error = try_break_deleg(inode, delegated_inode);
error = try_break_deleg(inode, 0, delegated_inode);
if (!error)
error = dir->i_op->link(old_dentry, dir, new_dentry);
}
@ -6043,21 +6043,24 @@ int vfs_rename(struct renamedata *rd)
old_dir->i_nlink >= max_links)
goto out;
}
error = try_break_deleg(old_dir, delegated_inode);
error = try_break_deleg(old_dir,
old_dir == new_dir ? LEASE_BREAK_DIR_RENAME :
LEASE_BREAK_DIR_DELETE,
delegated_inode);
if (error)
goto out;
if (new_dir != old_dir) {
error = try_break_deleg(new_dir, delegated_inode);
error = try_break_deleg(new_dir, LEASE_BREAK_DIR_CREATE, delegated_inode);
if (error)
goto out;
}
if (!is_dir) {
error = try_break_deleg(source, delegated_inode);
error = try_break_deleg(source, 0, delegated_inode);
if (error)
goto out;
}
if (target && !new_is_dir) {
error = try_break_deleg(target, delegated_inode);
error = try_break_deleg(target, 0, delegated_inode);
if (error)
goto out;
}

View File

@ -14,6 +14,9 @@
#include <linux/fsnotify_backend.h>
#include "fsnotify.h"
#define CREATE_TRACE_POINTS
#include <trace/events/fsnotify.h>
/*
* Clear all of the marks on an inode when it is being evicted from core
*/
@ -504,6 +507,8 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
int ret = 0;
__u32 test_mask, marks_mask = 0;
trace_fsnotify(mask, data, data_type, dir, file_name, inode, cookie);
if (path)
mnt = real_mount(path->mnt);

View File

@ -343,6 +343,35 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
fsnotify_conn_set_children_dentry_flags(conn);
}
/**
* fsnotify_modify_mark_mask - set and/or clear flags in a mark's mask
* @mark: mark to be modified
* @set: bits to be set in mask
* @clear: bits to be cleared in mask
*
* Modify a fsnotify_mark mask as directed, and update its associated conn.
* The caller is expected to hold a reference to the mark.
*/
void fsnotify_modify_mark_mask(struct fsnotify_mark *mark, u32 set, u32 clear)
{
bool recalc = false;
u32 mask;
WARN_ON_ONCE(clear & set);
spin_lock(&mark->lock);
mask = mark->mask;
mark->mask |= set;
mark->mask &= ~clear;
if (mark->mask != mask)
recalc = true;
spin_unlock(&mark->lock);
if (recalc)
fsnotify_recalc_mask(mark->connector);
}
EXPORT_SYMBOL_GPL(fsnotify_modify_mark_mask);
/* Free all connectors queued for freeing once SRCU period ends */
static void fsnotify_connector_destroy_workfn(struct work_struct *work)
{

View File

@ -1126,7 +1126,7 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
if (error)
goto out_inode_unlock;
error = try_break_deleg(inode, &delegated_inode);
error = try_break_deleg(inode, 0, &delegated_inode);
if (error)
goto out_inode_unlock;
@ -1234,7 +1234,7 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
if (error)
goto out_inode_unlock;
error = try_break_deleg(inode, &delegated_inode);
error = try_break_deleg(inode, 0, &delegated_inode);
if (error)
goto out_inode_unlock;

View File

@ -306,7 +306,7 @@ __vfs_setxattr_locked(struct mnt_idmap *idmap, struct dentry *dentry,
if (error)
goto out;
error = try_break_deleg(inode, delegated_inode);
error = try_break_deleg(inode, 0, delegated_inode);
if (error)
goto out;
@ -564,7 +564,7 @@ __vfs_removexattr_locked(struct mnt_idmap *idmap,
if (error)
goto out;
error = try_break_deleg(inode, delegated_inode);
error = try_break_deleg(inode, 0, delegated_inode);
if (error)
goto out;

View File

@ -4,19 +4,22 @@
#include <linux/fs.h>
#define FL_POSIX 1
#define FL_FLOCK 2
#define FL_DELEG 4 /* NFSv4 delegation */
#define FL_ACCESS 8 /* not trying to lock, just looking */
#define FL_EXISTS 16 /* when unlocking, test for existence */
#define FL_LEASE 32 /* lease held on this file */
#define FL_CLOSE 64 /* unlock on close */
#define FL_SLEEP 128 /* A blocking lock */
#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */
#define FL_UNLOCK_PENDING 512 /* Lease is being broken */
#define FL_OFDLCK 1024 /* lock is "owned" by struct file */
#define FL_LAYOUT 2048 /* outstanding pNFS layout */
#define FL_RECLAIM 4096 /* reclaiming from a reboot server */
#define FL_POSIX BIT(0) /* POSIX lock */
#define FL_FLOCK BIT(1) /* BSD lock */
#define FL_DELEG BIT(2) /* NFSv4 delegation */
#define FL_ACCESS BIT(3) /* not trying to lock, just looking */
#define FL_EXISTS BIT(4) /* when unlocking, test for existence */
#define FL_LEASE BIT(5) /* file lease */
#define FL_CLOSE BIT(6) /* unlock on close */
#define FL_SLEEP BIT(7) /* A blocking lock */
#define FL_DOWNGRADE_PENDING BIT(8) /* Lease is being downgraded */
#define FL_UNLOCK_PENDING BIT(9) /* Lease is being broken */
#define FL_OFDLCK BIT(10) /* POSIX lock "owned" by struct file */
#define FL_LAYOUT BIT(11) /* outstanding pNFS layout */
#define FL_RECLAIM BIT(12) /* reclaiming from a reboot server */
#define FL_IGN_DIR_CREATE BIT(13) /* ignore DIR_CREATE events */
#define FL_IGN_DIR_DELETE BIT(14) /* ignore DIR_DELETE events */
#define FL_IGN_DIR_RENAME BIT(15) /* ignore DIR_RENAME events */
#define FL_CLOSE_POSIX (FL_POSIX | FL_CLOSE)
@ -26,6 +29,15 @@
*/
#define FILE_LOCK_DEFERRED 1
#define LEASE_BREAK_LEASE BIT(0) // break leases and delegations
#define LEASE_BREAK_DELEG BIT(1) // break delegations only
#define LEASE_BREAK_LAYOUT BIT(2) // break layouts only
#define LEASE_BREAK_NONBLOCK BIT(3) // non-blocking break
#define LEASE_BREAK_OPEN_RDONLY BIT(4) // readonly open event
#define LEASE_BREAK_DIR_CREATE BIT(5) // dir deleg create event
#define LEASE_BREAK_DIR_DELETE BIT(6) // dir deleg delete event
#define LEASE_BREAK_DIR_RENAME BIT(7) // dir deleg rename event
struct file_lock;
struct file_lease;
@ -216,19 +228,13 @@ int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
void locks_init_lease(struct file_lease *);
void locks_free_lease(struct file_lease *fl);
struct file_lease *locks_alloc_lease(void);
#define LEASE_BREAK_LEASE BIT(0) // break leases and delegations
#define LEASE_BREAK_DELEG BIT(1) // break delegations only
#define LEASE_BREAK_LAYOUT BIT(2) // break layouts only
#define LEASE_BREAK_NONBLOCK BIT(3) // non-blocking break
#define LEASE_BREAK_OPEN_RDONLY BIT(4) // readonly open event
int __break_lease(struct inode *inode, unsigned int flags);
void lease_get_mtime(struct inode *, struct timespec64 *time);
int generic_setlease(struct file *, int, struct file_lease **, void **priv);
int kernel_setlease(struct file *, int, struct file_lease **, void **);
int vfs_setlease(struct file *, int, struct file_lease **, void **);
int lease_modify(struct file_lease *, int, struct list_head *);
u32 inode_lease_ignore_mask(struct inode *inode);
struct notifier_block;
int lease_register_notifier(struct notifier_block *);
@ -516,12 +522,26 @@ static inline bool is_delegated(struct delegated_inode *di)
return di->di_inode;
}
static inline int try_break_deleg(struct inode *inode,
/**
* try_break_deleg - do a non-blocking delegation break
* @inode: inode that should have its delegations broken
* @flags: extra LEASE_BREAK_* flags to pass to break_deleg()
* @di: returns pointer to delegated inode (may be NULL)
*
* Break delegations in a non-blocking fashion. If there are
* outstanding delegations and @di is set, then an extra reference
* will be taken on @inode and @di->di_inode will be populated so
* that it may be waited upon.
*
* Returns 0 if there is no need to wait or an error. If -EWOULDBLOCK
* is returned, then @di will be populated (if non-NULL).
*/
static inline int try_break_deleg(struct inode *inode, unsigned int flags,
struct delegated_inode *di)
{
int ret;
ret = break_deleg(inode, LEASE_BREAK_NONBLOCK);
ret = break_deleg(inode, flags | LEASE_BREAK_NONBLOCK);
if (ret == -EWOULDBLOCK && di) {
di->di_inode = inode;
ihold(inode);
@ -574,7 +594,7 @@ static inline int break_deleg(struct inode *inode, unsigned int flags)
return 0;
}
static inline int try_break_deleg(struct inode *inode,
static inline int try_break_deleg(struct inode *inode, unsigned int flags,
struct delegated_inode *delegated_inode)
{
return 0;

View File

@ -257,6 +257,10 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
__u32 new_dir_mask = FS_MOVED_TO;
__u32 rename_mask = FS_RENAME;
const struct qstr *new_name = &moved->d_name;
struct fsnotify_rename_data rd = {
.moved = moved,
.target = target,
};
if (isdir) {
old_dir_mask |= FS_ISDIR;
@ -265,12 +269,12 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
}
/* Event with information about both old and new parent+name */
fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY,
fsnotify_name(rename_mask, &rd, FSNOTIFY_EVENT_RENAME,
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,
fsnotify_name(new_dir_mask, &rd, FSNOTIFY_EVENT_RENAME,
new_dir, new_name, fs_cookie);
if (target)

View File

@ -311,6 +311,7 @@ enum fsnotify_data_type {
FSNOTIFY_EVENT_DENTRY,
FSNOTIFY_EVENT_MNT,
FSNOTIFY_EVENT_ERROR,
FSNOTIFY_EVENT_RENAME,
};
struct fs_error_report {
@ -335,6 +336,11 @@ struct fsnotify_mnt {
u64 mnt_id;
};
struct fsnotify_rename_data {
struct dentry *moved; /* the dentry that was renamed */
struct inode *target; /* inode overwritten by rename, or NULL */
};
static inline struct inode *fsnotify_data_inode(const void *data, int data_type)
{
switch (data_type) {
@ -348,6 +354,8 @@ static inline struct inode *fsnotify_data_inode(const void *data, int data_type)
return d_inode(file_range_path(data)->dentry);
case FSNOTIFY_EVENT_ERROR:
return ((struct fs_error_report *)data)->inode;
case FSNOTIFY_EVENT_RENAME:
return d_inode(((const struct fsnotify_rename_data *)data)->moved);
default:
return NULL;
}
@ -363,6 +371,8 @@ static inline struct dentry *fsnotify_data_dentry(const void *data, int data_typ
return ((const struct path *)data)->dentry;
case FSNOTIFY_EVENT_FILE_RANGE:
return file_range_path(data)->dentry;
case FSNOTIFY_EVENT_RENAME:
return ((struct fsnotify_rename_data *)data)->moved;
default:
return NULL;
}
@ -395,6 +405,8 @@ static inline struct super_block *fsnotify_data_sb(const void *data,
return file_range_path(data)->dentry->d_sb;
case FSNOTIFY_EVENT_ERROR:
return ((struct fs_error_report *) data)->sb;
case FSNOTIFY_EVENT_RENAME:
return ((const struct fsnotify_rename_data *)data)->moved->d_sb;
default:
return NULL;
}
@ -430,6 +442,14 @@ static inline struct fs_error_report *fsnotify_data_error_report(
}
}
static inline struct inode *fsnotify_data_rename_target(const void *data,
int data_type)
{
if (data_type == FSNOTIFY_EVENT_RENAME)
return ((const struct fsnotify_rename_data *)data)->target;
return NULL;
}
static inline const struct file_range *fsnotify_data_file_range(
const void *data,
int data_type)
@ -918,6 +938,7 @@ extern void fsnotify_put_mark(struct fsnotify_mark *mark);
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark);
extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info);
extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);
extern void fsnotify_modify_mark_mask(struct fsnotify_mark *mark, u32 set, u32 clear);
static inline void fsnotify_init_event(struct fsnotify_event *event)
{

View File

@ -28,7 +28,10 @@
{ FL_DOWNGRADE_PENDING, "FL_DOWNGRADE_PENDING" }, \
{ FL_UNLOCK_PENDING, "FL_UNLOCK_PENDING" }, \
{ FL_OFDLCK, "FL_OFDLCK" }, \
{ FL_RECLAIM, "FL_RECLAIM"})
{ FL_RECLAIM, "FL_RECLAIM" }, \
{ FL_IGN_DIR_CREATE, "FL_IGN_DIR_CREATE" }, \
{ FL_IGN_DIR_DELETE, "FL_IGN_DIR_DELETE" }, \
{ FL_IGN_DIR_RENAME, "FL_IGN_DIR_RENAME" })
#define show_fl_type(val) \
__print_symbolic(val, \
@ -117,6 +120,39 @@ DEFINE_EVENT(filelock_lock, flock_lock_inode,
TP_PROTO(struct inode *inode, struct file_lock *fl, int ret),
TP_ARGS(inode, fl, ret));
#define show_lease_break_flags(val) \
__print_flags(val, "|", \
{ LEASE_BREAK_LEASE, "LEASE" }, \
{ LEASE_BREAK_DELEG, "DELEG" }, \
{ LEASE_BREAK_LAYOUT, "LAYOUT" }, \
{ LEASE_BREAK_NONBLOCK, "NONBLOCK" }, \
{ LEASE_BREAK_OPEN_RDONLY, "OPEN_RDONLY" }, \
{ LEASE_BREAK_DIR_CREATE, "DIR_CREATE" }, \
{ LEASE_BREAK_DIR_DELETE, "DIR_DELETE" }, \
{ LEASE_BREAK_DIR_RENAME, "DIR_RENAME" })
TRACE_EVENT(break_lease,
TP_PROTO(struct inode *inode, unsigned int flags),
TP_ARGS(inode, flags),
TP_STRUCT__entry(
__field(unsigned long, i_ino)
__field(dev_t, s_dev)
__field(unsigned int, flags)
),
TP_fast_assign(
__entry->s_dev = inode->i_sb->s_dev;
__entry->i_ino = inode->i_ino;
__entry->flags = flags;
),
TP_printk("dev=0x%x:0x%x ino=0x%lx flags=%s",
MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
__entry->i_ino, show_lease_break_flags(__entry->flags))
);
DECLARE_EVENT_CLASS(filelock_lease,
TP_PROTO(struct inode *inode, struct file_lease *fl),

View File

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM fsnotify
#if !defined(_TRACE_FSNOTIFY_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_FSNOTIFY_H
#include <linux/tracepoint.h>
#include <trace/misc/fsnotify.h>
TRACE_EVENT(fsnotify,
TP_PROTO(__u32 mask, const void *data, int data_type,
struct inode *dir, const struct qstr *file_name,
struct inode *inode, u32 cookie),
TP_ARGS(mask, data, data_type, dir, file_name, inode, cookie),
TP_STRUCT__entry(
__field(__u32, mask)
__field(unsigned long, dir_ino)
__field(unsigned long, ino)
__field(dev_t, s_dev)
__field(int, data_type)
__field(u32, cookie)
__string(file_name, file_name ? (const char *)file_name->name : "")
),
TP_fast_assign(
__entry->mask = mask;
__entry->dir_ino = dir ? dir->i_ino : 0;
__entry->ino = inode ? inode->i_ino : 0;
__entry->s_dev = dir ? dir->i_sb->s_dev :
inode ? inode->i_sb->s_dev : 0;
__entry->data_type = data_type;
__entry->cookie = cookie;
__assign_str(file_name);
),
TP_printk("dev=%d:%d dir=%lu ino=%lu data_type=%d cookie=0x%x mask=0x%x %s name=%s",
MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
__entry->dir_ino, __entry->ino,
__entry->data_type, __entry->cookie,
__entry->mask, show_fsnotify_mask(__entry->mask),
__get_str(file_name))
);
#endif /* _TRACE_FSNOTIFY_H */
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Display helpers for fsnotify events
*/
#include <linux/fsnotify_backend.h>
#define show_fsnotify_mask(mask) \
__print_flags(mask, "|", \
{ FS_ACCESS, "ACCESS" }, \
{ FS_MODIFY, "MODIFY" }, \
{ FS_ATTRIB, "ATTRIB" }, \
{ FS_CLOSE_WRITE, "CLOSE_WRITE" }, \
{ FS_CLOSE_NOWRITE, "CLOSE_NOWRITE" }, \
{ FS_OPEN, "OPEN" }, \
{ FS_MOVED_FROM, "MOVED_FROM" }, \
{ FS_MOVED_TO, "MOVED_TO" }, \
{ FS_CREATE, "CREATE" }, \
{ FS_DELETE, "DELETE" }, \
{ FS_DELETE_SELF, "DELETE_SELF" }, \
{ FS_MOVE_SELF, "MOVE_SELF" }, \
{ FS_OPEN_EXEC, "OPEN_EXEC" }, \
{ FS_UNMOUNT, "UNMOUNT" }, \
{ FS_Q_OVERFLOW, "Q_OVERFLOW" }, \
{ FS_ERROR, "ERROR" }, \
{ FS_OPEN_PERM, "OPEN_PERM" }, \
{ FS_ACCESS_PERM, "ACCESS_PERM" }, \
{ FS_OPEN_EXEC_PERM, "OPEN_EXEC_PERM" }, \
{ FS_PRE_ACCESS, "PRE_ACCESS" }, \
{ FS_MNT_ATTACH, "MNT_ATTACH" }, \
{ FS_MNT_DETACH, "MNT_DETACH" }, \
{ FS_EVENT_ON_CHILD, "EVENT_ON_CHILD" }, \
{ FS_RENAME, "RENAME" }, \
{ FS_DN_MULTISHOT, "DN_MULTISHOT" }, \
{ FS_ISDIR, "ISDIR" })