mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	VFS: Change vfs_mkdir() to return the dentry.
vfs_mkdir() does not guarantee to leave the child dentry hashed or make it positive on success, and in many such cases the filesystem had to use a different dentry which it can now return. This patch changes vfs_mkdir() to return the dentry provided by the filesystems which is hashed and positive when provided. This reduces the number of cases where the resulting dentry is not positive to a handful which don't deserve extra efforts. The only callers of vfs_mkdir() which are interested in the resulting inode are in-kernel filesystem clients: cachefiles, nfsd, smb/server. The only filesystems that don't reliably provide the inode are: - kernfs, tracefs which these clients are unlikely to be interested in - cifs in some configurations would need to do a lookup to find the created inode, but doesn't. cifs cannot be exported via NFS, is unlikely to be used by cachefiles, and smb/server only has a soft requirement for the inode, so this is unlikely to be a problem in practice. - hostfs, nfs, cifs may need to do a lookup (rarely for NFS) and it is possible for a race to make that lookup fail. Actual failure is unlikely and providing callers handle negative dentries graceful they will fail-safe. So this patch removes the lookup code in nfsd and smb/server and adjusts them to fail safe if a negative dentry is provided: - cache-files already fails safe by restarting the task from the top - it still does with this change, though it no longer calls cachefiles_put_directory() as that will crash if the dentry is negative. - nfsd reports "Server-fault" which it what it used to do if the lookup failed. This will never happen on any file-systems that it can actually export, so this is of no consequence. I removed the fh_update() call as that is not needed and out-of-place. A subsequent nfsd_create_setattr() call will call fh_update() when needed. - smb/server only wants the inode to call ksmbd_smb_inherit_owner() which updates ->i_uid (without calling notify_change() or similar) which can be safely skipping on cifs (I hope). If a different dentry is returned, the first one is put. If necessary the fact that it is new can be determined by comparing pointers. A new dentry will certainly have a new pointer (as the old is put after the new is obtained). Similarly if an error is returned (via ERR_PTR()) the original dentry is put. Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: NeilBrown <neilb@suse.de> Link: https://lore.kernel.org/r/20250227013949.536172-7-neilb@suse.de Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
		
							parent
							
								
									8376583b84
								
							
						
					
					
						commit
						c54b386969
					
				
					 13 changed files with 104 additions and 127 deletions
				
			
		|  | @ -160,18 +160,17 @@ static int dev_mkdir(const char *name, umode_t mode) | ||||||
| { | { | ||||||
| 	struct dentry *dentry; | 	struct dentry *dentry; | ||||||
| 	struct path path; | 	struct path path; | ||||||
| 	int err; |  | ||||||
| 
 | 
 | ||||||
| 	dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY); | 	dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY); | ||||||
| 	if (IS_ERR(dentry)) | 	if (IS_ERR(dentry)) | ||||||
| 		return PTR_ERR(dentry); | 		return PTR_ERR(dentry); | ||||||
| 
 | 
 | ||||||
| 	err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode); | 	dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode); | ||||||
| 	if (!err) | 	if (!IS_ERR(dentry)) | ||||||
| 		/* mark as kernel-created inode */ | 		/* mark as kernel-created inode */ | ||||||
| 		d_inode(dentry)->i_private = &thread; | 		d_inode(dentry)->i_private = &thread; | ||||||
| 	done_path_create(&path, dentry); | 	done_path_create(&path, dentry); | ||||||
| 	return err; | 	return PTR_ERR_OR_ZERO(dentry); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int create_path(const char *nodepath) | static int create_path(const char *nodepath) | ||||||
|  |  | ||||||
|  | @ -128,18 +128,19 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, | ||||||
| 		ret = security_path_mkdir(&path, subdir, 0700); | 		ret = security_path_mkdir(&path, subdir, 0700); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
| 			goto mkdir_error; | 			goto mkdir_error; | ||||||
| 		ret = cachefiles_inject_write_error(); | 		subdir = ERR_PTR(cachefiles_inject_write_error()); | ||||||
| 		if (ret == 0) | 		if (!IS_ERR(subdir)) | ||||||
| 			ret = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700); | 			subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700); | ||||||
| 		if (ret < 0) { | 		ret = PTR_ERR(subdir); | ||||||
|  | 		if (IS_ERR(subdir)) { | ||||||
| 			trace_cachefiles_vfs_error(NULL, d_inode(dir), ret, | 			trace_cachefiles_vfs_error(NULL, d_inode(dir), ret, | ||||||
| 						   cachefiles_trace_mkdir_error); | 						   cachefiles_trace_mkdir_error); | ||||||
| 			goto mkdir_error; | 			goto mkdir_error; | ||||||
| 		} | 		} | ||||||
| 		trace_cachefiles_mkdir(dir, subdir); | 		trace_cachefiles_mkdir(dir, subdir); | ||||||
| 
 | 
 | ||||||
| 		if (unlikely(d_unhashed(subdir))) { | 		if (unlikely(d_unhashed(subdir) || d_is_negative(subdir))) { | ||||||
| 			cachefiles_put_directory(subdir); | 			dput(subdir); | ||||||
| 			goto retry; | 			goto retry; | ||||||
| 		} | 		} | ||||||
| 		ASSERT(d_backing_inode(subdir)); | 		ASSERT(d_backing_inode(subdir)); | ||||||
|  | @ -195,7 +196,8 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, | ||||||
| 
 | 
 | ||||||
| mkdir_error: | mkdir_error: | ||||||
| 	inode_unlock(d_inode(dir)); | 	inode_unlock(d_inode(dir)); | ||||||
| 	dput(subdir); | 	if (!IS_ERR(subdir)) | ||||||
|  | 		dput(subdir); | ||||||
| 	pr_err("mkdir %s failed with error %d\n", dirname, ret); | 	pr_err("mkdir %s failed with error %d\n", dirname, ret); | ||||||
| 	return ERR_PTR(ret); | 	return ERR_PTR(ret); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -511,10 +511,16 @@ static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, | ||||||
| 	struct inode *lower_dir; | 	struct inode *lower_dir; | ||||||
| 
 | 
 | ||||||
| 	rc = lock_parent(dentry, &lower_dentry, &lower_dir); | 	rc = lock_parent(dentry, &lower_dentry, &lower_dir); | ||||||
| 	if (!rc) | 	if (rc) | ||||||
| 		rc = vfs_mkdir(&nop_mnt_idmap, lower_dir, | 		goto out; | ||||||
| 			       lower_dentry, mode); | 
 | ||||||
| 	if (rc || d_really_is_negative(lower_dentry)) | 	lower_dentry = vfs_mkdir(&nop_mnt_idmap, lower_dir, | ||||||
|  | 				 lower_dentry, mode); | ||||||
|  | 	rc = PTR_ERR(lower_dentry); | ||||||
|  | 	if (IS_ERR(lower_dentry)) | ||||||
|  | 		goto out; | ||||||
|  | 	rc = 0; | ||||||
|  | 	if (d_unhashed(lower_dentry)) | ||||||
| 		goto out; | 		goto out; | ||||||
| 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); | 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); | ||||||
| 	if (rc) | 	if (rc) | ||||||
|  |  | ||||||
|  | @ -230,9 +230,12 @@ int __init init_mkdir(const char *pathname, umode_t mode) | ||||||
| 		return PTR_ERR(dentry); | 		return PTR_ERR(dentry); | ||||||
| 	mode = mode_strip_umask(d_inode(path.dentry), mode); | 	mode = mode_strip_umask(d_inode(path.dentry), mode); | ||||||
| 	error = security_path_mkdir(&path, dentry, mode); | 	error = security_path_mkdir(&path, dentry, mode); | ||||||
| 	if (!error) | 	if (!error) { | ||||||
| 		error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, | 		dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, | ||||||
| 				  dentry, mode); | 				  dentry, mode); | ||||||
|  | 		if (IS_ERR(dentry)) | ||||||
|  | 			error = PTR_ERR(dentry); | ||||||
|  | 	} | ||||||
| 	done_path_create(&path, dentry); | 	done_path_create(&path, dentry); | ||||||
| 	return error; | 	return error; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								fs/namei.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								fs/namei.c
									
									
									
									
									
								
							|  | @ -4128,7 +4128,8 @@ EXPORT_SYMBOL(kern_path_create); | ||||||
| 
 | 
 | ||||||
| void done_path_create(struct path *path, struct dentry *dentry) | void done_path_create(struct path *path, struct dentry *dentry) | ||||||
| { | { | ||||||
| 	dput(dentry); | 	if (!IS_ERR(dentry)) | ||||||
|  | 		dput(dentry); | ||||||
| 	inode_unlock(path->dentry->d_inode); | 	inode_unlock(path->dentry->d_inode); | ||||||
| 	mnt_drop_write(path->mnt); | 	mnt_drop_write(path->mnt); | ||||||
| 	path_put(path); | 	path_put(path); | ||||||
|  | @ -4274,7 +4275,7 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * vfs_mkdir - create directory |  * vfs_mkdir - create directory returning correct dentry if possible | ||||||
|  * @idmap:	idmap of the mount the inode was found from |  * @idmap:	idmap of the mount the inode was found from | ||||||
|  * @dir:	inode of the parent directory |  * @dir:	inode of the parent directory | ||||||
|  * @dentry:	dentry of the child directory |  * @dentry:	dentry of the child directory | ||||||
|  | @ -4287,9 +4288,15 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d | ||||||
|  * care to map the inode according to @idmap before checking permissions. |  * care to map the inode according to @idmap before checking permissions. | ||||||
|  * On non-idmapped mounts or if permission checking is to be performed on the |  * On non-idmapped mounts or if permission checking is to be performed on the | ||||||
|  * raw inode simply pass @nop_mnt_idmap. |  * raw inode simply pass @nop_mnt_idmap. | ||||||
|  |  * | ||||||
|  |  * In the event that the filesystem does not use the *@dentry but leaves it | ||||||
|  |  * negative or unhashes it and possibly splices a different one returning it, | ||||||
|  |  * the original dentry is dput() and the alternate is returned. | ||||||
|  |  * | ||||||
|  |  * In case of an error the dentry is dput() and an ERR_PTR() is returned. | ||||||
|  */ |  */ | ||||||
| int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, | struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, | ||||||
| 	      struct dentry *dentry, umode_t mode) | 			 struct dentry *dentry, umode_t mode) | ||||||
| { | { | ||||||
| 	int error; | 	int error; | ||||||
| 	unsigned max_links = dir->i_sb->s_max_links; | 	unsigned max_links = dir->i_sb->s_max_links; | ||||||
|  | @ -4297,31 +4304,35 @@ int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, | ||||||
| 
 | 
 | ||||||
| 	error = may_create(idmap, dir, dentry); | 	error = may_create(idmap, dir, dentry); | ||||||
| 	if (error) | 	if (error) | ||||||
| 		return error; | 		goto err; | ||||||
| 
 | 
 | ||||||
|  | 	error = -EPERM; | ||||||
| 	if (!dir->i_op->mkdir) | 	if (!dir->i_op->mkdir) | ||||||
| 		return -EPERM; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	mode = vfs_prepare_mode(idmap, dir, mode, S_IRWXUGO | S_ISVTX, 0); | 	mode = vfs_prepare_mode(idmap, dir, mode, S_IRWXUGO | S_ISVTX, 0); | ||||||
| 	error = security_inode_mkdir(dir, dentry, mode); | 	error = security_inode_mkdir(dir, dentry, mode); | ||||||
| 	if (error) | 	if (error) | ||||||
| 		return error; | 		goto err; | ||||||
| 
 | 
 | ||||||
|  | 	error = -EMLINK; | ||||||
| 	if (max_links && dir->i_nlink >= max_links) | 	if (max_links && dir->i_nlink >= max_links) | ||||||
| 		return -EMLINK; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	de = dir->i_op->mkdir(idmap, dir, dentry, mode); | 	de = dir->i_op->mkdir(idmap, dir, dentry, mode); | ||||||
|  | 	error = PTR_ERR(de); | ||||||
| 	if (IS_ERR(de)) | 	if (IS_ERR(de)) | ||||||
| 		return PTR_ERR(de); | 		goto err; | ||||||
| 	if (de) { | 	if (de) { | ||||||
| 		fsnotify_mkdir(dir, de); | 		dput(dentry); | ||||||
| 		/* Cannot return de yet */ | 		dentry = de; | ||||||
| 		dput(de); |  | ||||||
| 	} else { |  | ||||||
| 		fsnotify_mkdir(dir, dentry); |  | ||||||
| 	} | 	} | ||||||
|  | 	fsnotify_mkdir(dir, dentry); | ||||||
|  | 	return dentry; | ||||||
| 
 | 
 | ||||||
| 	return 0; | err: | ||||||
|  | 	dput(dentry); | ||||||
|  | 	return ERR_PTR(error); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(vfs_mkdir); | EXPORT_SYMBOL(vfs_mkdir); | ||||||
| 
 | 
 | ||||||
|  | @ -4341,8 +4352,10 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode) | ||||||
| 	error = security_path_mkdir(&path, dentry, | 	error = security_path_mkdir(&path, dentry, | ||||||
| 			mode_strip_umask(path.dentry->d_inode, mode)); | 			mode_strip_umask(path.dentry->d_inode, mode)); | ||||||
| 	if (!error) { | 	if (!error) { | ||||||
| 		error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, | 		dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, | ||||||
| 				  dentry, mode); | 				  dentry, mode); | ||||||
|  | 		if (IS_ERR(dentry)) | ||||||
|  | 			error = PTR_ERR(dentry); | ||||||
| 	} | 	} | ||||||
| 	done_path_create(&path, dentry); | 	done_path_create(&path, dentry); | ||||||
| 	if (retry_estale(error, lookup_flags)) { | 	if (retry_estale(error, lookup_flags)) { | ||||||
|  |  | ||||||
|  | @ -233,9 +233,12 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | ||||||
| 		 * as well be forgiving and just succeed silently. | 		 * as well be forgiving and just succeed silently. | ||||||
| 		 */ | 		 */ | ||||||
| 		goto out_put; | 		goto out_put; | ||||||
| 	status = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU); | 	dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU); | ||||||
|  | 	if (IS_ERR(dentry)) | ||||||
|  | 		status = PTR_ERR(dentry); | ||||||
| out_put: | out_put: | ||||||
| 	dput(dentry); | 	if (!status) | ||||||
|  | 		dput(dentry); | ||||||
| out_unlock: | out_unlock: | ||||||
| 	inode_unlock(d_inode(dir)); | 	inode_unlock(d_inode(dir)); | ||||||
| 	if (status == 0) { | 	if (status == 0) { | ||||||
|  |  | ||||||
|  | @ -1461,7 +1461,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||||||
| 	struct inode	*dirp; | 	struct inode	*dirp; | ||||||
| 	struct iattr	*iap = attrs->na_iattr; | 	struct iattr	*iap = attrs->na_iattr; | ||||||
| 	__be32		err; | 	__be32		err; | ||||||
| 	int		host_err; | 	int		host_err = 0; | ||||||
| 
 | 
 | ||||||
| 	dentry = fhp->fh_dentry; | 	dentry = fhp->fh_dentry; | ||||||
| 	dirp = d_inode(dentry); | 	dirp = d_inode(dentry); | ||||||
|  | @ -1488,25 +1488,15 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||||||
| 			nfsd_check_ignore_resizing(iap); | 			nfsd_check_ignore_resizing(iap); | ||||||
| 		break; | 		break; | ||||||
| 	case S_IFDIR: | 	case S_IFDIR: | ||||||
| 		host_err = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode); | 		dchild = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode); | ||||||
| 		if (!host_err && unlikely(d_unhashed(dchild))) { | 		if (IS_ERR(dchild)) { | ||||||
| 			struct dentry *d; | 			host_err = PTR_ERR(dchild); | ||||||
| 			d = lookup_one_len(dchild->d_name.name, | 		} else if (d_is_negative(dchild)) { | ||||||
| 					   dchild->d_parent, | 			err = nfserr_serverfault; | ||||||
| 					   dchild->d_name.len); | 			goto out; | ||||||
| 			if (IS_ERR(d)) { | 		} else if (unlikely(dchild != resfhp->fh_dentry)) { | ||||||
| 				host_err = PTR_ERR(d); |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 			if (unlikely(d_is_negative(d))) { |  | ||||||
| 				dput(d); |  | ||||||
| 				err = nfserr_serverfault; |  | ||||||
| 				goto out; |  | ||||||
| 			} |  | ||||||
| 			dput(resfhp->fh_dentry); | 			dput(resfhp->fh_dentry); | ||||||
| 			resfhp->fh_dentry = dget(d); | 			resfhp->fh_dentry = dget(dchild); | ||||||
| 			dput(dchild); |  | ||||||
| 			dchild = d; |  | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case S_IFCHR: | 	case S_IFCHR: | ||||||
|  | @ -1527,7 +1517,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||||||
| 	err = nfsd_create_setattr(rqstp, fhp, resfhp, attrs); | 	err = nfsd_create_setattr(rqstp, fhp, resfhp, attrs); | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
| 	dput(dchild); | 	if (!IS_ERR(dchild)) | ||||||
|  | 		dput(dchild); | ||||||
| 	return err; | 	return err; | ||||||
| 
 | 
 | ||||||
| out_nfserr: | out_nfserr: | ||||||
|  |  | ||||||
|  | @ -138,37 +138,6 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir, | ||||||
| 	goto out; | 	goto out; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir, |  | ||||||
| 		   struct dentry **newdentry, umode_t mode) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 	struct dentry *d, *dentry = *newdentry; |  | ||||||
| 
 |  | ||||||
| 	err = ovl_do_mkdir(ofs, dir, dentry, mode); |  | ||||||
| 	if (err) |  | ||||||
| 		return err; |  | ||||||
| 
 |  | ||||||
| 	if (likely(!d_unhashed(dentry))) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * vfs_mkdir() may succeed and leave the dentry passed |  | ||||||
| 	 * to it unhashed and negative. If that happens, try to |  | ||||||
| 	 * lookup a new hashed and positive dentry. |  | ||||||
| 	 */ |  | ||||||
| 	d = ovl_lookup_upper(ofs, dentry->d_name.name, dentry->d_parent, |  | ||||||
| 			     dentry->d_name.len); |  | ||||||
| 	if (IS_ERR(d)) { |  | ||||||
| 		pr_warn("failed lookup after mkdir (%pd2, err=%i).\n", |  | ||||||
| 			dentry, err); |  | ||||||
| 		return PTR_ERR(d); |  | ||||||
| 	} |  | ||||||
| 	dput(dentry); |  | ||||||
| 	*newdentry = d; |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, | struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, | ||||||
| 			       struct dentry *newdentry, struct ovl_cattr *attr) | 			       struct dentry *newdentry, struct ovl_cattr *attr) | ||||||
| { | { | ||||||
|  | @ -191,7 +160,8 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, | ||||||
| 
 | 
 | ||||||
| 		case S_IFDIR: | 		case S_IFDIR: | ||||||
| 			/* mkdir is special... */ | 			/* mkdir is special... */ | ||||||
| 			err =  ovl_mkdir_real(ofs, dir, &newdentry, attr->mode); | 			newdentry =  ovl_do_mkdir(ofs, dir, newdentry, attr->mode); | ||||||
|  | 			err = PTR_ERR_OR_ZERO(newdentry); | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		case S_IFCHR: | 		case S_IFCHR: | ||||||
|  | @ -219,7 +189,8 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir, | ||||||
| 	} | 	} | ||||||
| out: | out: | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		dput(newdentry); | 		if (!IS_ERR(newdentry)) | ||||||
|  | 			dput(newdentry); | ||||||
| 		return ERR_PTR(err); | 		return ERR_PTR(err); | ||||||
| 	} | 	} | ||||||
| 	return newdentry; | 	return newdentry; | ||||||
|  |  | ||||||
|  | @ -241,13 +241,14 @@ static inline int ovl_do_create(struct ovl_fs *ofs, | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int ovl_do_mkdir(struct ovl_fs *ofs, | static inline struct dentry *ovl_do_mkdir(struct ovl_fs *ofs, | ||||||
| 			       struct inode *dir, struct dentry *dentry, | 					  struct inode *dir, | ||||||
| 			       umode_t mode) | 					  struct dentry *dentry, | ||||||
|  | 					  umode_t mode) | ||||||
| { | { | ||||||
| 	int err = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode); | 	dentry = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode); | ||||||
| 	pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, err); | 	pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, PTR_ERR_OR_ZERO(dentry)); | ||||||
| 	return err; | 	return dentry; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int ovl_do_mknod(struct ovl_fs *ofs, | static inline int ovl_do_mknod(struct ovl_fs *ofs, | ||||||
|  | @ -838,8 +839,6 @@ struct ovl_cattr { | ||||||
| 
 | 
 | ||||||
| #define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) }) | #define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) }) | ||||||
| 
 | 
 | ||||||
| int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir, |  | ||||||
| 		   struct dentry **newdentry, umode_t mode); |  | ||||||
| struct dentry *ovl_create_real(struct ovl_fs *ofs, | struct dentry *ovl_create_real(struct ovl_fs *ofs, | ||||||
| 			       struct inode *dir, struct dentry *newdentry, | 			       struct inode *dir, struct dentry *newdentry, | ||||||
| 			       struct ovl_cattr *attr); | 			       struct ovl_cattr *attr); | ||||||
|  |  | ||||||
|  | @ -327,9 +327,10 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, | ||||||
| 			goto retry; | 			goto retry; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		err = ovl_mkdir_real(ofs, dir, &work, attr.ia_mode); | 		work = ovl_do_mkdir(ofs, dir, work, attr.ia_mode); | ||||||
| 		if (err) | 		err = PTR_ERR(work); | ||||||
| 			goto out_dput; | 		if (IS_ERR(work)) | ||||||
|  | 			goto out_err; | ||||||
| 
 | 
 | ||||||
| 		/* Weird filesystem returning with hashed negative (kernfs)? */ | 		/* Weird filesystem returning with hashed negative (kernfs)? */ | ||||||
| 		err = -EINVAL; | 		err = -EINVAL; | ||||||
|  |  | ||||||
|  | @ -206,8 +206,8 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) | ||||||
| { | { | ||||||
| 	struct mnt_idmap *idmap; | 	struct mnt_idmap *idmap; | ||||||
| 	struct path path; | 	struct path path; | ||||||
| 	struct dentry *dentry; | 	struct dentry *dentry, *d; | ||||||
| 	int err; | 	int err = 0; | ||||||
| 
 | 
 | ||||||
| 	dentry = ksmbd_vfs_kern_path_create(work, name, | 	dentry = ksmbd_vfs_kern_path_create(work, name, | ||||||
| 					    LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, | 					    LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY, | ||||||
|  | @ -222,27 +222,15 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) | ||||||
| 
 | 
 | ||||||
| 	idmap = mnt_idmap(path.mnt); | 	idmap = mnt_idmap(path.mnt); | ||||||
| 	mode |= S_IFDIR; | 	mode |= S_IFDIR; | ||||||
| 	err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); | 	d = dentry; | ||||||
| 	if (!err && d_unhashed(dentry)) { | 	dentry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); | ||||||
| 		struct dentry *d; | 	if (IS_ERR(dentry)) | ||||||
|  | 		err = PTR_ERR(dentry); | ||||||
|  | 	else if (d_is_negative(dentry)) | ||||||
|  | 		err = -ENOENT; | ||||||
|  | 	if (!err && dentry != d) | ||||||
|  | 		ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(dentry)); | ||||||
| 
 | 
 | ||||||
| 		d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent, |  | ||||||
| 			       dentry->d_name.len); |  | ||||||
| 		if (IS_ERR(d)) { |  | ||||||
| 			err = PTR_ERR(d); |  | ||||||
| 			goto out_err; |  | ||||||
| 		} |  | ||||||
| 		if (unlikely(d_is_negative(d))) { |  | ||||||
| 			dput(d); |  | ||||||
| 			err = -ENOENT; |  | ||||||
| 			goto out_err; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); |  | ||||||
| 		dput(d); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| out_err: |  | ||||||
| 	done_path_create(&path, dentry); | 	done_path_create(&path, dentry); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); | 		pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); | ||||||
|  |  | ||||||
|  | @ -167,10 +167,11 @@ xrep_orphanage_create( | ||||||
| 	 * directory to control access to a file we put in here. | 	 * directory to control access to a file we put in here. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (d_really_is_negative(orphanage_dentry)) { | 	if (d_really_is_negative(orphanage_dentry)) { | ||||||
| 		error = vfs_mkdir(&nop_mnt_idmap, root_inode, orphanage_dentry, | 		orphanage_dentry = vfs_mkdir(&nop_mnt_idmap, root_inode, | ||||||
| 				0750); | 					     orphanage_dentry, 0750); | ||||||
| 		if (error) | 		error = PTR_ERR(orphanage_dentry); | ||||||
| 			goto out_dput_orphanage; | 		if (IS_ERR(orphanage_dentry)) | ||||||
|  | 			goto out_unlock_root; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Not a directory? Bail out. */ | 	/* Not a directory? Bail out. */ | ||||||
|  |  | ||||||
|  | @ -1981,8 +1981,8 @@ bool inode_owner_or_capable(struct mnt_idmap *idmap, | ||||||
|  */ |  */ | ||||||
| int vfs_create(struct mnt_idmap *, struct inode *, | int vfs_create(struct mnt_idmap *, struct inode *, | ||||||
| 	       struct dentry *, umode_t, bool); | 	       struct dentry *, umode_t, bool); | ||||||
| int vfs_mkdir(struct mnt_idmap *, struct inode *, | struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *, | ||||||
| 	      struct dentry *, umode_t); | 			 struct dentry *, umode_t); | ||||||
| int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, | int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, | ||||||
|               umode_t, dev_t); |               umode_t, dev_t); | ||||||
| int vfs_symlink(struct mnt_idmap *, struct inode *, | int vfs_symlink(struct mnt_idmap *, struct inode *, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 NeilBrown
						NeilBrown