fs: remove the inode argument to ->d_real() method

The only remaining user of ->d_real() method is d_real_inode(), which
passed NULL inode argument to get the real data dentry.

There are no longer any users that call ->d_real() with a non-NULL
inode argument for getting a detry from a specific underlying layer.

Remove the inode argument of the method and replace it with an integer
'type' argument, to allow callers to request the real metadata dentry
instead of the real data dentry.

All the current users of d_real_inode() (e.g. uprobe) continue to get
the real data inode.  Caller that need to get the real metadata inode
(e.g. IMA/EVM) can use d_inode(d_real(dentry, D_REAL_METADATA)).

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://lore.kernel.org/r/20240202110132.1584111-3-amir73il@gmail.com
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Amir Goldstein 2024-02-02 13:01:32 +02:00 committed by Christian Brauner
parent 3058fca1ed
commit 11b3f8ae70
4 changed files with 41 additions and 47 deletions

View File

@ -29,7 +29,7 @@ prototypes::
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
struct vfsmount *(*d_automount)(struct path *path); struct vfsmount *(*d_automount)(struct path *path);
int (*d_manage)(const struct path *, bool); int (*d_manage)(const struct path *, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *); struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
locking rules: locking rules:

View File

@ -1264,7 +1264,7 @@ defined:
char *(*d_dname)(struct dentry *, char *, int); char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *); struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(const struct path *, bool); int (*d_manage)(const struct path *, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *); struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
}; };
``d_revalidate`` ``d_revalidate``
@ -1419,16 +1419,14 @@ defined:
the dentry being transited from. the dentry being transited from.
``d_real`` ``d_real``
overlay/union type filesystems implement this method to return overlay/union type filesystems implement this method to return one
one of the underlying dentries hidden by the overlay. It is of the underlying dentries of a regular file hidden by the overlay.
used in two different modes:
Called from file_dentry() it returns the real dentry matching The 'type' argument takes the values D_REAL_DATA or D_REAL_METADATA
the inode argument. The real dentry may be from a lower layer for returning the real underlying dentry that refers to the inode
already copied up, but still referenced from the file. This hosting the file's data or metadata respectively.
mode is selected with a non-NULL inode argument.
With NULL inode the topmost real underlying dentry is returned. For non-regular files, the 'dentry' argument is returned.
Each dentry has a pointer to its parent dentry, as well as a hash list Each dentry has a pointer to its parent dentry, as well as a hash list
of child dentries. Child dentries are basically like files in a of child dentries. Child dentries are basically like files in a

View File

@ -28,41 +28,38 @@ MODULE_LICENSE("GPL");
struct ovl_dir_cache; struct ovl_dir_cache;
static struct dentry *ovl_d_real(struct dentry *dentry, static struct dentry *ovl_d_real(struct dentry *dentry, enum d_real_type type)
const struct inode *inode)
{ {
struct dentry *real = NULL, *lower; struct dentry *upper, *lower;
int err; int err;
/* switch (type) {
* vfs is only expected to call d_real() with NULL from d_real_inode() case D_REAL_DATA:
* and with overlay inode from file_dentry() on an overlay file. case D_REAL_METADATA:
* break;
* TODO: remove @inode argument from d_real() API, remove code in this default:
* function that deals with non-NULL @inode and remove d_real() call
* from file_dentry().
*/
if (inode && d_inode(dentry) == inode)
return dentry;
else if (inode)
goto bug; goto bug;
}
if (!d_is_reg(dentry)) { if (!d_is_reg(dentry)) {
/* d_real_inode() is only relevant for regular files */ /* d_real_inode() is only relevant for regular files */
return dentry; return dentry;
} }
real = ovl_dentry_upper(dentry); upper = ovl_dentry_upper(dentry);
if (real && (inode == d_inode(real))) if (upper && (type == D_REAL_METADATA ||
return real; ovl_has_upperdata(d_inode(dentry))))
return upper;
if (real && !inode && ovl_has_upperdata(d_inode(dentry))) if (type == D_REAL_METADATA) {
return real; lower = ovl_dentry_lower(dentry);
goto real_lower;
}
/* /*
* Best effort lazy lookup of lowerdata for !inode case to return * Best effort lazy lookup of lowerdata for D_REAL_DATA case to return
* the real lowerdata dentry. The only current caller of d_real() with * the real lowerdata dentry. The only current caller of d_real() with
* NULL inode is d_real_inode() from trace_uprobe and this caller is * D_REAL_DATA is d_real_inode() from trace_uprobe and this caller is
* likely going to be followed reading from the file, before placing * likely going to be followed reading from the file, before placing
* uprobes on offset within the file, so lowerdata should be available * uprobes on offset within the file, so lowerdata should be available
* when setting the uprobe. * when setting the uprobe.
@ -73,18 +70,13 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
lower = ovl_dentry_lowerdata(dentry); lower = ovl_dentry_lowerdata(dentry);
if (!lower) if (!lower)
goto bug; goto bug;
real = lower;
/* Handle recursion */ real_lower:
real = d_real(real, inode); /* Handle recursion into stacked lower fs */
return d_real(lower, type);
if (!inode || inode == d_inode(real))
return real;
bug: bug:
WARN(1, "%s(%pd4, %s:%lu): real dentry (%p/%lu) not found\n", WARN(1, "%s(%pd4, %d): real dentry not found\n", __func__, dentry, type);
__func__, dentry, inode ? inode->i_sb->s_id : "NULL",
inode ? inode->i_ino : 0, real,
real && d_inode(real) ? d_inode(real)->i_ino : 0);
return dentry; return dentry;
} }

View File

@ -125,6 +125,11 @@ enum dentry_d_lock_class
DENTRY_D_LOCK_NESTED DENTRY_D_LOCK_NESTED
}; };
enum d_real_type {
D_REAL_DATA,
D_REAL_METADATA,
};
struct dentry_operations { struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int); int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int); int (*d_weak_revalidate)(struct dentry *, unsigned int);
@ -139,7 +144,7 @@ struct dentry_operations {
char *(*d_dname)(struct dentry *, char *, int); char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *); struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(const struct path *, bool); int (*d_manage)(const struct path *, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *); struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
} ____cacheline_aligned; } ____cacheline_aligned;
/* /*
@ -546,24 +551,23 @@ static inline struct inode *d_backing_inode(const struct dentry *upper)
/** /**
* d_real - Return the real dentry * d_real - Return the real dentry
* @dentry: the dentry to query * @dentry: the dentry to query
* @inode: inode to select the dentry from multiple layers (can be NULL) * @type: the type of real dentry (data or metadata)
* *
* If dentry is on a union/overlay, then return the underlying, real dentry. * If dentry is on a union/overlay, then return the underlying, real dentry.
* Otherwise return the dentry itself. * Otherwise return the dentry itself.
* *
* See also: Documentation/filesystems/vfs.rst * See also: Documentation/filesystems/vfs.rst
*/ */
static inline struct dentry *d_real(struct dentry *dentry, static inline struct dentry *d_real(struct dentry *dentry, enum d_real_type type)
const struct inode *inode)
{ {
if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
return dentry->d_op->d_real(dentry, inode); return dentry->d_op->d_real(dentry, type);
else else
return dentry; return dentry;
} }
/** /**
* d_real_inode - Return the real inode * d_real_inode - Return the real inode hosting the data
* @dentry: The dentry to query * @dentry: The dentry to query
* *
* If dentry is on a union/overlay, then return the underlying, real inode. * If dentry is on a union/overlay, then return the underlying, real inode.
@ -572,7 +576,7 @@ static inline struct dentry *d_real(struct dentry *dentry,
static inline struct inode *d_real_inode(const struct dentry *dentry) static inline struct inode *d_real_inode(const struct dentry *dentry)
{ {
/* This usage of d_real() results in const dentry */ /* This usage of d_real() results in const dentry */
return d_backing_inode(d_real((struct dentry *) dentry, NULL)); return d_inode(d_real((struct dentry *) dentry, D_REAL_DATA));
} }
struct name_snapshot { struct name_snapshot {