Skip to content

Commit e079d7c

Browse files
Christoph Hellwigbrauner
authored andcommitted
devtmpfs: don't use vfs_getattr_nosec to query i_mode
The recent move of the bdev_statx call to the low-level vfs_getattr_nosec helper caused it being used by devtmpfs, which leads to deadlocks in md teardown due to the block device lookup and put interfering with the unusual lifetime rules in md. But as handle_remove only works on inodes created and owned by devtmpfs itself there is no need to use vfs_getattr_nosec vs simply reading the mode from the inode directly. Switch to that to avoid the bdev lookup or any other unintentional side effect. Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> Reported-by: Xiao Ni <xni@redhat.com> Fixes: 777d096 ("fs: move the bdex_statx call to vfs_getattr_nosec") Signed-off-by: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/20250423045941.1667425-1-hch@lst.de Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> Tested-by: Xiao Ni <xni@redhat.com> Tested-by: Ayush Jain <Ayush.jain3@amd.com> Tested-by: Heiko Carstens <hca@linux.ibm.com> Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 0d039ea commit e079d7c

File tree

1 file changed

+9
-13
lines changed

1 file changed

+9
-13
lines changed

drivers/base/devtmpfs.c

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -296,21 +296,21 @@ static int delete_path(const char *nodepath)
296296
return err;
297297
}
298298

299-
static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
299+
static int dev_mynode(struct device *dev, struct inode *inode)
300300
{
301301
/* did we create it */
302302
if (inode->i_private != &thread)
303303
return 0;
304304

305305
/* does the dev_t match */
306306
if (is_blockdev(dev)) {
307-
if (!S_ISBLK(stat->mode))
307+
if (!S_ISBLK(inode->i_mode))
308308
return 0;
309309
} else {
310-
if (!S_ISCHR(stat->mode))
310+
if (!S_ISCHR(inode->i_mode))
311311
return 0;
312312
}
313-
if (stat->rdev != dev->devt)
313+
if (inode->i_rdev != dev->devt)
314314
return 0;
315315

316316
/* ours */
@@ -321,28 +321,24 @@ static int handle_remove(const char *nodename, struct device *dev)
321321
{
322322
struct path parent;
323323
struct dentry *dentry;
324-
struct kstat stat;
325-
struct path p;
324+
struct inode *inode;
326325
int deleted = 0;
327-
int err;
326+
int err = 0;
328327

329328
dentry = kern_path_locked(nodename, &parent);
330329
if (IS_ERR(dentry))
331330
return PTR_ERR(dentry);
332331

333-
p.mnt = parent.mnt;
334-
p.dentry = dentry;
335-
err = vfs_getattr(&p, &stat, STATX_TYPE | STATX_MODE,
336-
AT_STATX_SYNC_AS_STAT);
337-
if (!err && dev_mynode(dev, d_inode(dentry), &stat)) {
332+
inode = d_inode(dentry);
333+
if (dev_mynode(dev, inode)) {
338334
struct iattr newattrs;
339335
/*
340336
* before unlinking this node, reset permissions
341337
* of possible references like hardlinks
342338
*/
343339
newattrs.ia_uid = GLOBAL_ROOT_UID;
344340
newattrs.ia_gid = GLOBAL_ROOT_GID;
345-
newattrs.ia_mode = stat.mode & ~0777;
341+
newattrs.ia_mode = inode->i_mode & ~0777;
346342
newattrs.ia_valid =
347343
ATTR_UID|ATTR_GID|ATTR_MODE;
348344
inode_lock(d_inode(dentry));

0 commit comments

Comments
 (0)