mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02:00 
			
		
		
		
	VFS: change kern_path_locked() and user_path_locked_at() to never return negative dentry
No callers of kern_path_locked() or user_path_locked_at() want a
negative dentry.  So change them to return -ENOENT instead.  This
simplifies callers.
This results in a subtle change to bcachefs in that an ioctl will now
return -ENOENT in preference to -EXDEV.  I believe this restores the
behaviour to what it was prior to
 Commit bbe6a7c899 ("bch2_ioctl_subvolume_destroy(): fix locking")
Signed-off-by: NeilBrown <neilb@suse.de>
Link: https://lore.kernel.org/r/20250217003020.3170652-2-neilb@suse.de
Acked-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									2c3230fb8d
								
							
						
					
					
						commit
						1c3cb50b58
					
				
					 5 changed files with 48 additions and 45 deletions
				
			
		|  | @ -1157,3 +1157,11 @@ in normal case it points into the pathname being looked up. | ||||||
| NOTE: if you need something like full path from the root of filesystem, | NOTE: if you need something like full path from the root of filesystem, | ||||||
| you are still on your own - this assists with simple cases, but it's not | you are still on your own - this assists with simple cases, but it's not | ||||||
| magic. | magic. | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ** recommended** | ||||||
|  | 
 | ||||||
|  | kern_path_locked() and user_path_locked() no longer return a negative | ||||||
|  | dentry so this doesn't need to be checked.  If the name cannot be found, | ||||||
|  | ERR_PTR(-ENOENT) is returned. | ||||||
|  |  | ||||||
|  | @ -245,15 +245,12 @@ static int dev_rmdir(const char *name) | ||||||
| 	dentry = kern_path_locked(name, &parent); | 	dentry = kern_path_locked(name, &parent); | ||||||
| 	if (IS_ERR(dentry)) | 	if (IS_ERR(dentry)) | ||||||
| 		return PTR_ERR(dentry); | 		return PTR_ERR(dentry); | ||||||
| 	if (d_really_is_positive(dentry)) { | 	if (d_inode(dentry)->i_private == &thread) | ||||||
| 		if (d_inode(dentry)->i_private == &thread) | 		err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry), | ||||||
| 			err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry), | 				dentry); | ||||||
| 					dentry); | 	else | ||||||
| 		else | 		err = -EPERM; | ||||||
| 			err = -EPERM; | 
 | ||||||
| 	} else { |  | ||||||
| 		err = -ENOENT; |  | ||||||
| 	} |  | ||||||
| 	dput(dentry); | 	dput(dentry); | ||||||
| 	inode_unlock(d_inode(parent.dentry)); | 	inode_unlock(d_inode(parent.dentry)); | ||||||
| 	path_put(&parent); | 	path_put(&parent); | ||||||
|  | @ -310,6 +307,8 @@ static int handle_remove(const char *nodename, struct device *dev) | ||||||
| { | { | ||||||
| 	struct path parent; | 	struct path parent; | ||||||
| 	struct dentry *dentry; | 	struct dentry *dentry; | ||||||
|  | 	struct kstat stat; | ||||||
|  | 	struct path p; | ||||||
| 	int deleted = 0; | 	int deleted = 0; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
|  | @ -317,32 +316,28 @@ static int handle_remove(const char *nodename, struct device *dev) | ||||||
| 	if (IS_ERR(dentry)) | 	if (IS_ERR(dentry)) | ||||||
| 		return PTR_ERR(dentry); | 		return PTR_ERR(dentry); | ||||||
| 
 | 
 | ||||||
| 	if (d_really_is_positive(dentry)) { | 	p.mnt = parent.mnt; | ||||||
| 		struct kstat stat; | 	p.dentry = dentry; | ||||||
| 		struct path p = {.mnt = parent.mnt, .dentry = dentry}; | 	err = vfs_getattr(&p, &stat, STATX_TYPE | STATX_MODE, | ||||||
| 		err = vfs_getattr(&p, &stat, STATX_TYPE | STATX_MODE, | 			  AT_STATX_SYNC_AS_STAT); | ||||||
| 				  AT_STATX_SYNC_AS_STAT); | 	if (!err && dev_mynode(dev, d_inode(dentry), &stat)) { | ||||||
| 		if (!err && dev_mynode(dev, d_inode(dentry), &stat)) { | 		struct iattr newattrs; | ||||||
| 			struct iattr newattrs; | 		/*
 | ||||||
| 			/*
 | 		 * before unlinking this node, reset permissions | ||||||
| 			 * before unlinking this node, reset permissions | 		 * of possible references like hardlinks | ||||||
| 			 * of possible references like hardlinks | 		 */ | ||||||
| 			 */ | 		newattrs.ia_uid = GLOBAL_ROOT_UID; | ||||||
| 			newattrs.ia_uid = GLOBAL_ROOT_UID; | 		newattrs.ia_gid = GLOBAL_ROOT_GID; | ||||||
| 			newattrs.ia_gid = GLOBAL_ROOT_GID; | 		newattrs.ia_mode = stat.mode & ~0777; | ||||||
| 			newattrs.ia_mode = stat.mode & ~0777; | 		newattrs.ia_valid = | ||||||
| 			newattrs.ia_valid = | 			ATTR_UID|ATTR_GID|ATTR_MODE; | ||||||
| 				ATTR_UID|ATTR_GID|ATTR_MODE; | 		inode_lock(d_inode(dentry)); | ||||||
| 			inode_lock(d_inode(dentry)); | 		notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL); | ||||||
| 			notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL); | 		inode_unlock(d_inode(dentry)); | ||||||
| 			inode_unlock(d_inode(dentry)); | 		err = vfs_unlink(&nop_mnt_idmap, d_inode(parent.dentry), | ||||||
| 			err = vfs_unlink(&nop_mnt_idmap, d_inode(parent.dentry), | 				 dentry, NULL); | ||||||
| 					 dentry, NULL); | 		if (!err || err == -ENOENT) | ||||||
| 			if (!err || err == -ENOENT) | 			deleted = 1; | ||||||
| 				deleted = 1; |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		err = -ENOENT; |  | ||||||
| 	} | 	} | ||||||
| 	dput(dentry); | 	dput(dentry); | ||||||
| 	inode_unlock(d_inode(parent.dentry)); | 	inode_unlock(d_inode(parent.dentry)); | ||||||
|  |  | ||||||
|  | @ -511,10 +511,6 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp, | ||||||
| 		ret = -EXDEV; | 		ret = -EXDEV; | ||||||
| 		goto err; | 		goto err; | ||||||
| 	} | 	} | ||||||
| 	if (!d_is_positive(victim)) { |  | ||||||
| 		ret = -ENOENT; |  | ||||||
| 		goto err; |  | ||||||
| 	} |  | ||||||
| 	ret = __bch2_unlink(dir, victim, true); | 	ret = __bch2_unlink(dir, victim, true); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		fsnotify_rmdir(dir, victim); | 		fsnotify_rmdir(dir, victim); | ||||||
|  |  | ||||||
|  | @ -2741,6 +2741,10 @@ static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct | ||||||
| 	} | 	} | ||||||
| 	inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); | 	inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); | ||||||
| 	d = lookup_one_qstr_excl(&last, path->dentry, 0); | 	d = lookup_one_qstr_excl(&last, path->dentry, 0); | ||||||
|  | 	if (!IS_ERR(d) && d_is_negative(d)) { | ||||||
|  | 		dput(d); | ||||||
|  | 		d = ERR_PTR(-ENOENT); | ||||||
|  | 	} | ||||||
| 	if (IS_ERR(d)) { | 	if (IS_ERR(d)) { | ||||||
| 		inode_unlock(path->dentry->d_inode); | 		inode_unlock(path->dentry->d_inode); | ||||||
| 		path_put(path); | 		path_put(path); | ||||||
|  |  | ||||||
|  | @ -350,11 +350,10 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent) | ||||||
| 	struct dentry *d = kern_path_locked(watch->path, parent); | 	struct dentry *d = kern_path_locked(watch->path, parent); | ||||||
| 	if (IS_ERR(d)) | 	if (IS_ERR(d)) | ||||||
| 		return PTR_ERR(d); | 		return PTR_ERR(d); | ||||||
| 	if (d_is_positive(d)) { | 	/* update watch filter fields */ | ||||||
| 		/* update watch filter fields */ | 	watch->dev = d->d_sb->s_dev; | ||||||
| 		watch->dev = d->d_sb->s_dev; | 	watch->ino = d_backing_inode(d)->i_ino; | ||||||
| 		watch->ino = d_backing_inode(d)->i_ino; | 
 | ||||||
| 	} |  | ||||||
| 	inode_unlock(d_backing_inode(parent->dentry)); | 	inode_unlock(d_backing_inode(parent->dentry)); | ||||||
| 	dput(d); | 	dput(d); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -419,10 +418,11 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list) | ||||||
| 	/* caller expects mutex locked */ | 	/* caller expects mutex locked */ | ||||||
| 	mutex_lock(&audit_filter_mutex); | 	mutex_lock(&audit_filter_mutex); | ||||||
| 
 | 
 | ||||||
| 	if (ret) { | 	if (ret && ret != -ENOENT) { | ||||||
| 		audit_put_watch(watch); | 		audit_put_watch(watch); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
|  | 	ret = 0; | ||||||
| 
 | 
 | ||||||
| 	/* either find an old parent or attach a new one */ | 	/* either find an old parent or attach a new one */ | ||||||
| 	parent = audit_find_parent(d_backing_inode(parent_path.dentry)); | 	parent = audit_find_parent(d_backing_inode(parent_path.dentry)); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 NeilBrown
						NeilBrown