brintos

brintos / linux-shallow public Read only

0
0
Text · 45.5 KiB · 7cbd580 Raw
1962 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *   Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>4 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.5 */6 7#include <linux/kernel.h>8#include <linux/fs.h>9#include <linux/filelock.h>10#include <linux/uaccess.h>11#include <linux/backing-dev.h>12#include <linux/writeback.h>13#include <linux/xattr.h>14#include <linux/falloc.h>15#include <linux/fsnotify.h>16#include <linux/dcache.h>17#include <linux/slab.h>18#include <linux/vmalloc.h>19#include <linux/sched/xacct.h>20#include <linux/crc32c.h>21#include <linux/namei.h>22 23#include "glob.h"24#include "oplock.h"25#include "connection.h"26#include "vfs.h"27#include "vfs_cache.h"28#include "smbacl.h"29#include "ndr.h"30#include "auth.h"31#include "misc.h"32 33#include "smb_common.h"34#include "mgmt/share_config.h"35#include "mgmt/tree_connect.h"36#include "mgmt/user_session.h"37#include "mgmt/user_config.h"38 39static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work,40				    struct inode *parent_inode,41				    struct inode *inode)42{43	if (!test_share_config_flag(work->tcon->share_conf,44				    KSMBD_SHARE_FLAG_INHERIT_OWNER))45		return;46 47	i_uid_write(inode, i_uid_read(parent_inode));48}49 50/**51 * ksmbd_vfs_lock_parent() - lock parent dentry if it is stable52 * @parent: parent dentry53 * @child: child dentry54 *55 * Returns: %0 on success, %-ENOENT if the parent dentry is not stable56 */57int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child)58{59	inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);60	if (child->d_parent != parent) {61		inode_unlock(d_inode(parent));62		return -ENOENT;63	}64 65	return 0;66}67 68static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,69					char *pathname, unsigned int flags,70					struct path *parent_path,71					struct path *path)72{73	struct qstr last;74	struct filename *filename;75	struct path *root_share_path = &share_conf->vfs_path;76	int err, type;77	struct dentry *d;78 79	if (pathname[0] == '\0') {80		pathname = share_conf->path;81		root_share_path = NULL;82	} else {83		flags |= LOOKUP_BENEATH;84	}85 86	filename = getname_kernel(pathname);87	if (IS_ERR(filename))88		return PTR_ERR(filename);89 90	err = vfs_path_parent_lookup(filename, flags,91				     parent_path, &last, &type,92				     root_share_path);93	if (err) {94		putname(filename);95		return err;96	}97 98	if (unlikely(type != LAST_NORM)) {99		path_put(parent_path);100		putname(filename);101		return -ENOENT;102	}103 104	err = mnt_want_write(parent_path->mnt);105	if (err) {106		path_put(parent_path);107		putname(filename);108		return -ENOENT;109	}110 111	inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT);112	d = lookup_one_qstr_excl(&last, parent_path->dentry, 0);113	if (IS_ERR(d))114		goto err_out;115 116	if (d_is_negative(d)) {117		dput(d);118		goto err_out;119	}120 121	path->dentry = d;122	path->mnt = mntget(parent_path->mnt);123 124	if (test_share_config_flag(share_conf, KSMBD_SHARE_FLAG_CROSSMNT)) {125		err = follow_down(path, 0);126		if (err < 0) {127			path_put(path);128			goto err_out;129		}130	}131 132	putname(filename);133	return 0;134 135err_out:136	inode_unlock(d_inode(parent_path->dentry));137	mnt_drop_write(parent_path->mnt);138	path_put(parent_path);139	putname(filename);140	return -ENOENT;141}142 143void ksmbd_vfs_query_maximal_access(struct mnt_idmap *idmap,144				   struct dentry *dentry, __le32 *daccess)145{146	*daccess = cpu_to_le32(FILE_READ_ATTRIBUTES | READ_CONTROL);147 148	if (!inode_permission(idmap, d_inode(dentry), MAY_OPEN | MAY_WRITE))149		*daccess |= cpu_to_le32(WRITE_DAC | WRITE_OWNER | SYNCHRONIZE |150				FILE_WRITE_DATA | FILE_APPEND_DATA |151				FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES |152				FILE_DELETE_CHILD);153 154	if (!inode_permission(idmap, d_inode(dentry), MAY_OPEN | MAY_READ))155		*daccess |= FILE_READ_DATA_LE | FILE_READ_EA_LE;156 157	if (!inode_permission(idmap, d_inode(dentry), MAY_OPEN | MAY_EXEC))158		*daccess |= FILE_EXECUTE_LE;159 160	if (!inode_permission(idmap, d_inode(dentry->d_parent), MAY_EXEC | MAY_WRITE))161		*daccess |= FILE_DELETE_LE;162}163 164/**165 * ksmbd_vfs_create() - vfs helper for smb create file166 * @work:	work167 * @name:	file name that is relative to share168 * @mode:	file create mode169 *170 * Return:	0 on success, otherwise error171 */172int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)173{174	struct path path;175	struct dentry *dentry;176	int err;177 178	dentry = ksmbd_vfs_kern_path_create(work, name,179					    LOOKUP_NO_SYMLINKS, &path);180	if (IS_ERR(dentry)) {181		err = PTR_ERR(dentry);182		if (err != -ENOENT)183			pr_err("path create failed for %s, err %d\n",184			       name, err);185		return err;186	}187 188	mode |= S_IFREG;189	err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry),190			 dentry, mode, true);191	if (!err) {192		ksmbd_vfs_inherit_owner(work, d_inode(path.dentry),193					d_inode(dentry));194	} else {195		pr_err("File(%s): creation failed (err:%d)\n", name, err);196	}197 198	done_path_create(&path, dentry);199	return err;200}201 202/**203 * ksmbd_vfs_mkdir() - vfs helper for smb create directory204 * @work:	work205 * @name:	directory name that is relative to share206 * @mode:	directory create mode207 *208 * Return:	0 on success, otherwise error209 */210int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)211{212	struct mnt_idmap *idmap;213	struct path path;214	struct dentry *dentry;215	int err;216 217	dentry = ksmbd_vfs_kern_path_create(work, name,218					    LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY,219					    &path);220	if (IS_ERR(dentry)) {221		err = PTR_ERR(dentry);222		if (err != -EEXIST)223			ksmbd_debug(VFS, "path create failed for %s, err %d\n",224				    name, err);225		return err;226	}227 228	idmap = mnt_idmap(path.mnt);229	mode |= S_IFDIR;230	err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);231	if (!err && d_unhashed(dentry)) {232		struct dentry *d;233 234		d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent,235			       dentry->d_name.len);236		if (IS_ERR(d)) {237			err = PTR_ERR(d);238			goto out_err;239		}240		if (unlikely(d_is_negative(d))) {241			dput(d);242			err = -ENOENT;243			goto out_err;244		}245 246		ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d));247		dput(d);248	}249 250out_err:251	done_path_create(&path, dentry);252	if (err)253		pr_err("mkdir(%s): creation failed (err:%d)\n", name, err);254	return err;255}256 257static ssize_t ksmbd_vfs_getcasexattr(struct mnt_idmap *idmap,258				      struct dentry *dentry, char *attr_name,259				      int attr_name_len, char **attr_value)260{261	char *name, *xattr_list = NULL;262	ssize_t value_len = -ENOENT, xattr_list_len;263 264	xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list);265	if (xattr_list_len <= 0)266		goto out;267 268	for (name = xattr_list; name - xattr_list < xattr_list_len;269			name += strlen(name) + 1) {270		ksmbd_debug(VFS, "%s, len %zd\n", name, strlen(name));271		if (strncasecmp(attr_name, name, attr_name_len))272			continue;273 274		value_len = ksmbd_vfs_getxattr(idmap,275					       dentry,276					       name,277					       attr_value);278		if (value_len < 0)279			pr_err("failed to get xattr in file\n");280		break;281	}282 283out:284	kvfree(xattr_list);285	return value_len;286}287 288static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos,289				 size_t count)290{291	ssize_t v_len;292	char *stream_buf = NULL;293 294	ksmbd_debug(VFS, "read stream data pos : %llu, count : %zd\n",295		    *pos, count);296 297	v_len = ksmbd_vfs_getcasexattr(file_mnt_idmap(fp->filp),298				       fp->filp->f_path.dentry,299				       fp->stream.name,300				       fp->stream.size,301				       &stream_buf);302	if ((int)v_len <= 0)303		return (int)v_len;304 305	if (v_len <= *pos) {306		count = -EINVAL;307		goto free_buf;308	}309 310	if (v_len - *pos < count)311		count = v_len - *pos;312 313	memcpy(buf, &stream_buf[*pos], count);314 315free_buf:316	kvfree(stream_buf);317	return count;318}319 320/**321 * check_lock_range() - vfs helper for smb byte range file locking322 * @filp:	the file to apply the lock to323 * @start:	lock start byte offset324 * @end:	lock end byte offset325 * @type:	byte range type read/write326 *327 * Return:	0 on success, otherwise error328 */329static int check_lock_range(struct file *filp, loff_t start, loff_t end,330			    unsigned char type)331{332	struct file_lock *flock;333	struct file_lock_context *ctx = locks_inode_context(file_inode(filp));334	int error = 0;335 336	if (!ctx || list_empty_careful(&ctx->flc_posix))337		return 0;338 339	spin_lock(&ctx->flc_lock);340	for_each_file_lock(flock, &ctx->flc_posix) {341		/* check conflict locks */342		if (flock->fl_end >= start && end >= flock->fl_start) {343			if (lock_is_read(flock)) {344				if (type == WRITE) {345					pr_err("not allow write by shared lock\n");346					error = 1;347					goto out;348				}349			} else if (lock_is_write(flock)) {350				/* check owner in lock */351				if (flock->c.flc_file != filp) {352					error = 1;353					pr_err("not allow rw access by exclusive lock from other opens\n");354					goto out;355				}356			}357		}358	}359out:360	spin_unlock(&ctx->flc_lock);361	return error;362}363 364/**365 * ksmbd_vfs_read() - vfs helper for smb file read366 * @work:	smb work367 * @fp:		ksmbd file pointer368 * @count:	read byte count369 * @pos:	file pos370 * @rbuf:	read data buffer371 *372 * Return:	number of read bytes on success, otherwise error373 */374int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,375		   loff_t *pos, char *rbuf)376{377	struct file *filp = fp->filp;378	ssize_t nbytes = 0;379	struct inode *inode = file_inode(filp);380 381	if (S_ISDIR(inode->i_mode))382		return -EISDIR;383 384	if (unlikely(count == 0))385		return 0;386 387	if (work->conn->connection_type) {388		if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) {389			pr_err("no right to read(%pD)\n", fp->filp);390			return -EACCES;391		}392	}393 394	if (ksmbd_stream_fd(fp))395		return ksmbd_vfs_stream_read(fp, rbuf, pos, count);396 397	if (!work->tcon->posix_extensions) {398		int ret;399 400		ret = check_lock_range(filp, *pos, *pos + count - 1, READ);401		if (ret) {402			pr_err("unable to read due to lock\n");403			return -EAGAIN;404		}405	}406 407	nbytes = kernel_read(filp, rbuf, count, pos);408	if (nbytes < 0) {409		pr_err("smb read failed, err = %zd\n", nbytes);410		return nbytes;411	}412 413	filp->f_pos = *pos;414	return nbytes;415}416 417static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,418				  size_t count)419{420	char *stream_buf = NULL, *wbuf;421	struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);422	size_t size;423	ssize_t v_len;424	int err = 0;425 426	ksmbd_debug(VFS, "write stream data pos : %llu, count : %zd\n",427		    *pos, count);428 429	size = *pos + count;430	if (size > XATTR_SIZE_MAX) {431		size = XATTR_SIZE_MAX;432		count = (*pos + count) - XATTR_SIZE_MAX;433	}434 435	v_len = ksmbd_vfs_getcasexattr(idmap,436				       fp->filp->f_path.dentry,437				       fp->stream.name,438				       fp->stream.size,439				       &stream_buf);440	if (v_len < 0) {441		pr_err("not found stream in xattr : %zd\n", v_len);442		err = v_len;443		goto out;444	}445 446	if (v_len < size) {447		wbuf = kvzalloc(size, GFP_KERNEL);448		if (!wbuf) {449			err = -ENOMEM;450			goto out;451		}452 453		if (v_len > 0)454			memcpy(wbuf, stream_buf, v_len);455		kvfree(stream_buf);456		stream_buf = wbuf;457	}458 459	memcpy(&stream_buf[*pos], buf, count);460 461	err = ksmbd_vfs_setxattr(idmap,462				 &fp->filp->f_path,463				 fp->stream.name,464				 (void *)stream_buf,465				 size,466				 0,467				 true);468	if (err < 0)469		goto out;470 471	fp->filp->f_pos = *pos;472	err = 0;473out:474	kvfree(stream_buf);475	return err;476}477 478/**479 * ksmbd_vfs_write() - vfs helper for smb file write480 * @work:	work481 * @fp:		ksmbd file pointer482 * @buf:	buf containing data for writing483 * @count:	read byte count484 * @pos:	file pos485 * @sync:	fsync after write486 * @written:	number of bytes written487 *488 * Return:	0 on success, otherwise error489 */490int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,491		    char *buf, size_t count, loff_t *pos, bool sync,492		    ssize_t *written)493{494	struct file *filp;495	loff_t	offset = *pos;496	int err = 0;497 498	if (work->conn->connection_type) {499		if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) {500			pr_err("no right to write(%pD)\n", fp->filp);501			err = -EACCES;502			goto out;503		}504	}505 506	filp = fp->filp;507 508	if (ksmbd_stream_fd(fp)) {509		err = ksmbd_vfs_stream_write(fp, buf, pos, count);510		if (!err)511			*written = count;512		goto out;513	}514 515	if (!work->tcon->posix_extensions) {516		err = check_lock_range(filp, *pos, *pos + count - 1, WRITE);517		if (err) {518			pr_err("unable to write due to lock\n");519			err = -EAGAIN;520			goto out;521		}522	}523 524	/* Reserve lease break for parent dir at closing time */525	fp->reserve_lease_break = true;526 527	/* Do we need to break any of a levelII oplock? */528	smb_break_all_levII_oplock(work, fp, 1);529 530	err = kernel_write(filp, buf, count, pos);531	if (err < 0) {532		ksmbd_debug(VFS, "smb write failed, err = %d\n", err);533		goto out;534	}535 536	filp->f_pos = *pos;537	*written = err;538	err = 0;539	if (sync) {540		err = vfs_fsync_range(filp, offset, offset + *written, 0);541		if (err < 0)542			pr_err("fsync failed for filename = %pD, err = %d\n",543			       fp->filp, err);544	}545 546out:547	return err;548}549 550/**551 * ksmbd_vfs_getattr() - vfs helper for smb getattr552 * @path:	path of dentry553 * @stat:	pointer to returned kernel stat structure554 * Return:	0 on success, otherwise error555 */556int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat)557{558	int err;559 560	err = vfs_getattr(path, stat, STATX_BTIME, AT_STATX_SYNC_AS_STAT);561	if (err)562		pr_err("getattr failed, err %d\n", err);563	return err;564}565 566/**567 * ksmbd_vfs_fsync() - vfs helper for smb fsync568 * @work:	work569 * @fid:	file id of open file570 * @p_id:	persistent file id571 *572 * Return:	0 on success, otherwise error573 */574int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id)575{576	struct ksmbd_file *fp;577	int err;578 579	fp = ksmbd_lookup_fd_slow(work, fid, p_id);580	if (!fp) {581		pr_err("failed to get filp for fid %llu\n", fid);582		return -ENOENT;583	}584	err = vfs_fsync(fp->filp, 0);585	if (err < 0)586		pr_err("smb fsync failed, err = %d\n", err);587	ksmbd_fd_put(work, fp);588	return err;589}590 591/**592 * ksmbd_vfs_remove_file() - vfs helper for smb rmdir or unlink593 * @work:	work594 * @path:	path of dentry595 *596 * Return:	0 on success, otherwise error597 */598int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)599{600	struct mnt_idmap *idmap;601	struct dentry *parent = path->dentry->d_parent;602	int err;603 604	if (ksmbd_override_fsids(work))605		return -ENOMEM;606 607	if (!d_inode(path->dentry)->i_nlink) {608		err = -ENOENT;609		goto out_err;610	}611 612	idmap = mnt_idmap(path->mnt);613	if (S_ISDIR(d_inode(path->dentry)->i_mode)) {614		err = vfs_rmdir(idmap, d_inode(parent), path->dentry);615		if (err && err != -ENOTEMPTY)616			ksmbd_debug(VFS, "rmdir failed, err %d\n", err);617	} else {618		err = vfs_unlink(idmap, d_inode(parent), path->dentry, NULL);619		if (err)620			ksmbd_debug(VFS, "unlink failed, err %d\n", err);621	}622 623out_err:624	ksmbd_revert_fsids(work);625	return err;626}627 628/**629 * ksmbd_vfs_link() - vfs helper for creating smb hardlink630 * @work:	work631 * @oldname:	source file name632 * @newname:	hardlink name that is relative to share633 *634 * Return:	0 on success, otherwise error635 */636int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,637		   const char *newname)638{639	struct path oldpath, newpath;640	struct dentry *dentry;641	int err;642 643	if (ksmbd_override_fsids(work))644		return -ENOMEM;645 646	err = kern_path(oldname, LOOKUP_NO_SYMLINKS, &oldpath);647	if (err) {648		pr_err("cannot get linux path for %s, err = %d\n",649		       oldname, err);650		goto out1;651	}652 653	dentry = ksmbd_vfs_kern_path_create(work, newname,654					    LOOKUP_NO_SYMLINKS | LOOKUP_REVAL,655					    &newpath);656	if (IS_ERR(dentry)) {657		err = PTR_ERR(dentry);658		pr_err("path create err for %s, err %d\n", newname, err);659		goto out2;660	}661 662	err = -EXDEV;663	if (oldpath.mnt != newpath.mnt) {664		pr_err("vfs_link failed err %d\n", err);665		goto out3;666	}667 668	err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt),669		       d_inode(newpath.dentry),670		       dentry, NULL);671	if (err)672		ksmbd_debug(VFS, "vfs_link failed err %d\n", err);673 674out3:675	done_path_create(&newpath, dentry);676out2:677	path_put(&oldpath);678out1:679	ksmbd_revert_fsids(work);680	return err;681}682 683int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,684		     char *newname, int flags)685{686	struct dentry *old_parent, *new_dentry, *trap;687	struct dentry *old_child = old_path->dentry;688	struct path new_path;689	struct qstr new_last;690	struct renamedata rd;691	struct filename *to;692	struct ksmbd_share_config *share_conf = work->tcon->share_conf;693	struct ksmbd_file *parent_fp;694	int new_type;695	int err, lookup_flags = LOOKUP_NO_SYMLINKS;696 697	if (ksmbd_override_fsids(work))698		return -ENOMEM;699 700	to = getname_kernel(newname);701	if (IS_ERR(to)) {702		err = PTR_ERR(to);703		goto revert_fsids;704	}705 706retry:707	err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH,708				     &new_path, &new_last, &new_type,709				     &share_conf->vfs_path);710	if (err)711		goto out1;712 713	if (old_path->mnt != new_path.mnt) {714		err = -EXDEV;715		goto out2;716	}717 718	err = mnt_want_write(old_path->mnt);719	if (err)720		goto out2;721 722	trap = lock_rename_child(old_child, new_path.dentry);723	if (IS_ERR(trap)) {724		err = PTR_ERR(trap);725		goto out_drop_write;726	}727 728	old_parent = dget(old_child->d_parent);729	if (d_unhashed(old_child)) {730		err = -EINVAL;731		goto out3;732	}733 734	parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);735	if (parent_fp) {736		if (parent_fp->daccess & FILE_DELETE_LE) {737			pr_err("parent dir is opened with delete access\n");738			err = -ESHARE;739			ksmbd_fd_put(work, parent_fp);740			goto out3;741		}742		ksmbd_fd_put(work, parent_fp);743	}744 745	new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry,746					  lookup_flags | LOOKUP_RENAME_TARGET);747	if (IS_ERR(new_dentry)) {748		err = PTR_ERR(new_dentry);749		goto out3;750	}751 752	if (d_is_symlink(new_dentry)) {753		err = -EACCES;754		goto out4;755	}756 757	/*758	 * explicitly handle file overwrite case, for compatibility with759	 * filesystems that may not support rename flags (e.g: fuse)760	 */761	if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) {762		err = -EEXIST;763		goto out4;764	}765	flags &= ~(RENAME_NOREPLACE);766 767	if (old_child == trap) {768		err = -EINVAL;769		goto out4;770	}771 772	if (new_dentry == trap) {773		err = -ENOTEMPTY;774		goto out4;775	}776 777	rd.old_mnt_idmap	= mnt_idmap(old_path->mnt),778	rd.old_dir		= d_inode(old_parent),779	rd.old_dentry		= old_child,780	rd.new_mnt_idmap	= mnt_idmap(new_path.mnt),781	rd.new_dir		= new_path.dentry->d_inode,782	rd.new_dentry		= new_dentry,783	rd.flags		= flags,784	rd.delegated_inode	= NULL,785	err = vfs_rename(&rd);786	if (err)787		ksmbd_debug(VFS, "vfs_rename failed err %d\n", err);788 789out4:790	dput(new_dentry);791out3:792	dput(old_parent);793	unlock_rename(old_parent, new_path.dentry);794out_drop_write:795	mnt_drop_write(old_path->mnt);796out2:797	path_put(&new_path);798 799	if (retry_estale(err, lookup_flags)) {800		lookup_flags |= LOOKUP_REVAL;801		goto retry;802	}803out1:804	putname(to);805revert_fsids:806	ksmbd_revert_fsids(work);807	return err;808}809 810/**811 * ksmbd_vfs_truncate() - vfs helper for smb file truncate812 * @work:	work813 * @fp:		ksmbd file pointer814 * @size:	truncate to given size815 *816 * Return:	0 on success, otherwise error817 */818int ksmbd_vfs_truncate(struct ksmbd_work *work,819		       struct ksmbd_file *fp, loff_t size)820{821	int err = 0;822	struct file *filp;823 824	filp = fp->filp;825 826	/* Do we need to break any of a levelII oplock? */827	smb_break_all_levII_oplock(work, fp, 1);828 829	if (!work->tcon->posix_extensions) {830		struct inode *inode = file_inode(filp);831 832		if (size < inode->i_size) {833			err = check_lock_range(filp, size,834					       inode->i_size - 1, WRITE);835		} else {836			err = check_lock_range(filp, inode->i_size,837					       size - 1, WRITE);838		}839 840		if (err) {841			pr_err("failed due to lock\n");842			return -EAGAIN;843		}844	}845 846	err = vfs_truncate(&filp->f_path, size);847	if (err)848		pr_err("truncate failed, err %d\n", err);849	return err;850}851 852/**853 * ksmbd_vfs_listxattr() - vfs helper for smb list extended attributes854 * @dentry:	dentry of file for listing xattrs855 * @list:	destination buffer856 *857 * Return:	xattr list length on success, otherwise error858 */859ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list)860{861	ssize_t size;862	char *vlist = NULL;863 864	size = vfs_listxattr(dentry, NULL, 0);865	if (size <= 0)866		return size;867 868	vlist = kvzalloc(size, GFP_KERNEL);869	if (!vlist)870		return -ENOMEM;871 872	*list = vlist;873	size = vfs_listxattr(dentry, vlist, size);874	if (size < 0) {875		ksmbd_debug(VFS, "listxattr failed\n");876		kvfree(vlist);877		*list = NULL;878	}879 880	return size;881}882 883static ssize_t ksmbd_vfs_xattr_len(struct mnt_idmap *idmap,884				   struct dentry *dentry, char *xattr_name)885{886	return vfs_getxattr(idmap, dentry, xattr_name, NULL, 0);887}888 889/**890 * ksmbd_vfs_getxattr() - vfs helper for smb get extended attributes value891 * @idmap:	idmap892 * @dentry:	dentry of file for getting xattrs893 * @xattr_name:	name of xattr name to query894 * @xattr_buf:	destination buffer xattr value895 *896 * Return:	read xattr value length on success, otherwise error897 */898ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,899			   struct dentry *dentry,900			   char *xattr_name, char **xattr_buf)901{902	ssize_t xattr_len;903	char *buf;904 905	*xattr_buf = NULL;906	xattr_len = ksmbd_vfs_xattr_len(idmap, dentry, xattr_name);907	if (xattr_len < 0)908		return xattr_len;909 910	buf = kmalloc(xattr_len + 1, GFP_KERNEL);911	if (!buf)912		return -ENOMEM;913 914	xattr_len = vfs_getxattr(idmap, dentry, xattr_name,915				 (void *)buf, xattr_len);916	if (xattr_len > 0)917		*xattr_buf = buf;918	else919		kfree(buf);920	return xattr_len;921}922 923/**924 * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value925 * @idmap:	idmap of the relevant mount926 * @path:	path of dentry to set XATTR at927 * @attr_name:	xattr name for setxattr928 * @attr_value:	xattr value to set929 * @attr_size:	size of xattr value930 * @flags:	destination buffer length931 * @get_write:	get write access to a mount932 *933 * Return:	0 on success, otherwise error934 */935int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,936		       const struct path *path, const char *attr_name,937		       void *attr_value, size_t attr_size, int flags,938		       bool get_write)939{940	int err;941 942	if (get_write == true) {943		err = mnt_want_write(path->mnt);944		if (err)945			return err;946	}947 948	err = vfs_setxattr(idmap,949			   path->dentry,950			   attr_name,951			   attr_value,952			   attr_size,953			   flags);954	if (err)955		ksmbd_debug(VFS, "setxattr failed, err %d\n", err);956	if (get_write == true)957		mnt_drop_write(path->mnt);958	return err;959}960 961/**962 * ksmbd_vfs_set_fadvise() - convert smb IO caching options to linux options963 * @filp:	file pointer for IO964 * @option:	smb IO options965 */966void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option)967{968	struct address_space *mapping;969 970	mapping = filp->f_mapping;971 972	if (!option || !mapping)973		return;974 975	if (option & FILE_WRITE_THROUGH_LE) {976		filp->f_flags |= O_SYNC;977	} else if (option & FILE_SEQUENTIAL_ONLY_LE) {978		filp->f_ra.ra_pages = inode_to_bdi(mapping->host)->ra_pages * 2;979		spin_lock(&filp->f_lock);980		filp->f_mode &= ~FMODE_RANDOM;981		spin_unlock(&filp->f_lock);982	} else if (option & FILE_RANDOM_ACCESS_LE) {983		spin_lock(&filp->f_lock);984		filp->f_mode |= FMODE_RANDOM;985		spin_unlock(&filp->f_lock);986	}987}988 989int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,990			loff_t off, loff_t len)991{992	smb_break_all_levII_oplock(work, fp, 1);993	if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_SPARSE_FILE_LE)994		return vfs_fallocate(fp->filp,995				     FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,996				     off, len);997 998	return vfs_fallocate(fp->filp,999			     FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,1000			     off, len);1001}1002 1003int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,1004			 struct file_allocated_range_buffer *ranges,1005			 unsigned int in_count, unsigned int *out_count)1006{1007	struct file *f = fp->filp;1008	struct inode *inode = file_inode(fp->filp);1009	loff_t maxbytes = (u64)inode->i_sb->s_maxbytes, end;1010	loff_t extent_start, extent_end;1011	int ret = 0;1012 1013	if (start > maxbytes)1014		return -EFBIG;1015 1016	if (!in_count)1017		return 0;1018 1019	/*1020	 * Shrink request scope to what the fs can actually handle.1021	 */1022	if (length > maxbytes || (maxbytes - length) < start)1023		length = maxbytes - start;1024 1025	if (start + length > inode->i_size)1026		length = inode->i_size - start;1027 1028	*out_count = 0;1029	end = start + length;1030	while (start < end && *out_count < in_count) {1031		extent_start = vfs_llseek(f, start, SEEK_DATA);1032		if (extent_start < 0) {1033			if (extent_start != -ENXIO)1034				ret = (int)extent_start;1035			break;1036		}1037 1038		if (extent_start >= end)1039			break;1040 1041		extent_end = vfs_llseek(f, extent_start, SEEK_HOLE);1042		if (extent_end < 0) {1043			if (extent_end != -ENXIO)1044				ret = (int)extent_end;1045			break;1046		} else if (extent_start >= extent_end) {1047			break;1048		}1049 1050		ranges[*out_count].file_offset = cpu_to_le64(extent_start);1051		ranges[(*out_count)++].length =1052			cpu_to_le64(min(extent_end, end) - extent_start);1053 1054		start = extent_end;1055	}1056 1057	return ret;1058}1059 1060int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,1061			   const struct path *path, char *attr_name,1062			   bool get_write)1063{1064	int err;1065 1066	if (get_write == true) {1067		err = mnt_want_write(path->mnt);1068		if (err)1069			return err;1070	}1071 1072	err = vfs_removexattr(idmap, path->dentry, attr_name);1073 1074	if (get_write == true)1075		mnt_drop_write(path->mnt);1076 1077	return err;1078}1079 1080int ksmbd_vfs_unlink(struct file *filp)1081{1082	int err = 0;1083	struct dentry *dir, *dentry = filp->f_path.dentry;1084	struct mnt_idmap *idmap = file_mnt_idmap(filp);1085 1086	err = mnt_want_write(filp->f_path.mnt);1087	if (err)1088		return err;1089 1090	dir = dget_parent(dentry);1091	err = ksmbd_vfs_lock_parent(dir, dentry);1092	if (err)1093		goto out;1094	dget(dentry);1095 1096	if (S_ISDIR(d_inode(dentry)->i_mode))1097		err = vfs_rmdir(idmap, d_inode(dir), dentry);1098	else1099		err = vfs_unlink(idmap, d_inode(dir), dentry, NULL);1100 1101	dput(dentry);1102	inode_unlock(d_inode(dir));1103	if (err)1104		ksmbd_debug(VFS, "failed to delete, err %d\n", err);1105out:1106	dput(dir);1107	mnt_drop_write(filp->f_path.mnt);1108 1109	return err;1110}1111 1112static bool __dir_empty(struct dir_context *ctx, const char *name, int namlen,1113		       loff_t offset, u64 ino, unsigned int d_type)1114{1115	struct ksmbd_readdir_data *buf;1116 1117	buf = container_of(ctx, struct ksmbd_readdir_data, ctx);1118	if (!is_dot_dotdot(name, namlen))1119		buf->dirent_count++;1120 1121	return !buf->dirent_count;1122}1123 1124/**1125 * ksmbd_vfs_empty_dir() - check for empty directory1126 * @fp:	ksmbd file pointer1127 *1128 * Return:	true if directory empty, otherwise false1129 */1130int ksmbd_vfs_empty_dir(struct ksmbd_file *fp)1131{1132	int err;1133	struct ksmbd_readdir_data readdir_data;1134 1135	memset(&readdir_data, 0, sizeof(struct ksmbd_readdir_data));1136 1137	set_ctx_actor(&readdir_data.ctx, __dir_empty);1138	readdir_data.dirent_count = 0;1139 1140	err = iterate_dir(fp->filp, &readdir_data.ctx);1141	if (readdir_data.dirent_count)1142		err = -ENOTEMPTY;1143	else1144		err = 0;1145	return err;1146}1147 1148static bool __caseless_lookup(struct dir_context *ctx, const char *name,1149			     int namlen, loff_t offset, u64 ino,1150			     unsigned int d_type)1151{1152	struct ksmbd_readdir_data *buf;1153	int cmp = -EINVAL;1154 1155	buf = container_of(ctx, struct ksmbd_readdir_data, ctx);1156 1157	if (buf->used != namlen)1158		return true;1159	if (IS_ENABLED(CONFIG_UNICODE) && buf->um) {1160		const struct qstr q_buf = {.name = buf->private,1161					   .len = buf->used};1162		const struct qstr q_name = {.name = name,1163					    .len = namlen};1164 1165		cmp = utf8_strncasecmp(buf->um, &q_buf, &q_name);1166	}1167	if (cmp < 0)1168		cmp = strncasecmp((char *)buf->private, name, namlen);1169	if (!cmp) {1170		memcpy((char *)buf->private, name, buf->used);1171		buf->dirent_count = 1;1172		return false;1173	}1174	return true;1175}1176 1177/**1178 * ksmbd_vfs_lookup_in_dir() - lookup a file in a directory1179 * @dir:	path info1180 * @name:	filename to lookup1181 * @namelen:	filename length1182 * @um:		&struct unicode_map to use1183 *1184 * Return:	0 on success, otherwise error1185 */1186static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,1187				   size_t namelen, struct unicode_map *um)1188{1189	int ret;1190	struct file *dfilp;1191	int flags = O_RDONLY | O_LARGEFILE;1192	struct ksmbd_readdir_data readdir_data = {1193		.ctx.actor	= __caseless_lookup,1194		.private	= name,1195		.used		= namelen,1196		.dirent_count	= 0,1197		.um		= um,1198	};1199 1200	dfilp = dentry_open(dir, flags, current_cred());1201	if (IS_ERR(dfilp))1202		return PTR_ERR(dfilp);1203 1204	ret = iterate_dir(dfilp, &readdir_data.ctx);1205	if (readdir_data.dirent_count > 0)1206		ret = 0;1207	fput(dfilp);1208	return ret;1209}1210 1211/**1212 * ksmbd_vfs_kern_path_locked() - lookup a file and get path info1213 * @work:	work1214 * @name:		file path that is relative to share1215 * @flags:		lookup flags1216 * @parent_path:	if lookup succeed, return parent_path info1217 * @path:		if lookup succeed, return path info1218 * @caseless:	caseless filename lookup1219 *1220 * Return:	0 on success, otherwise error1221 */1222int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,1223			       unsigned int flags, struct path *parent_path,1224			       struct path *path, bool caseless)1225{1226	struct ksmbd_share_config *share_conf = work->tcon->share_conf;1227	int err;1228 1229	err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, parent_path,1230					   path);1231	if (!err)1232		return 0;1233 1234	if (caseless) {1235		char *filepath;1236		size_t path_len, remain_len;1237 1238		filepath = name;1239		path_len = strlen(filepath);1240		remain_len = path_len;1241 1242		*parent_path = share_conf->vfs_path;1243		path_get(parent_path);1244 1245		while (d_can_lookup(parent_path->dentry)) {1246			char *filename = filepath + path_len - remain_len;1247			char *next = strchrnul(filename, '/');1248			size_t filename_len = next - filename;1249			bool is_last = !next[0];1250 1251			if (filename_len == 0)1252				break;1253 1254			err = ksmbd_vfs_lookup_in_dir(parent_path, filename,1255						      filename_len,1256						      work->conn->um);1257			if (err)1258				goto out2;1259 1260			next[0] = '\0';1261 1262			err = vfs_path_lookup(share_conf->vfs_path.dentry,1263					      share_conf->vfs_path.mnt,1264					      filepath,1265					      flags,1266					      path);1267			if (err)1268				goto out2;1269			else if (is_last)1270				goto out1;1271			path_put(parent_path);1272			*parent_path = *path;1273 1274			next[0] = '/';1275			remain_len -= filename_len + 1;1276		}1277 1278		err = -EINVAL;1279out2:1280		path_put(parent_path);1281	}1282 1283out1:1284	if (!err) {1285		err = mnt_want_write(parent_path->mnt);1286		if (err) {1287			path_put(path);1288			path_put(parent_path);1289			return err;1290		}1291 1292		err = ksmbd_vfs_lock_parent(parent_path->dentry, path->dentry);1293		if (err) {1294			path_put(path);1295			path_put(parent_path);1296		}1297	}1298	return err;1299}1300 1301void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path)1302{1303	inode_unlock(d_inode(parent_path->dentry));1304	mnt_drop_write(parent_path->mnt);1305	path_put(path);1306	path_put(parent_path);1307}1308 1309struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,1310					  const char *name,1311					  unsigned int flags,1312					  struct path *path)1313{1314	char *abs_name;1315	struct dentry *dent;1316 1317	abs_name = convert_to_unix_name(work->tcon->share_conf, name);1318	if (!abs_name)1319		return ERR_PTR(-ENOMEM);1320 1321	dent = kern_path_create(AT_FDCWD, abs_name, path, flags);1322	kfree(abs_name);1323	return dent;1324}1325 1326int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,1327				const struct path *path)1328{1329	char *name, *xattr_list = NULL;1330	ssize_t xattr_list_len;1331	int err = 0;1332 1333	xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);1334	if (xattr_list_len < 0) {1335		goto out;1336	} else if (!xattr_list_len) {1337		ksmbd_debug(SMB, "empty xattr in the file\n");1338		goto out;1339	}1340 1341	err = mnt_want_write(path->mnt);1342	if (err)1343		goto out;1344 1345	for (name = xattr_list; name - xattr_list < xattr_list_len;1346	     name += strlen(name) + 1) {1347		ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));1348 1349		if (!strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS,1350			     sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) ||1351		    !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,1352			     sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {1353			err = vfs_remove_acl(idmap, path->dentry, name);1354			if (err)1355				ksmbd_debug(SMB,1356					    "remove acl xattr failed : %s\n", name);1357		}1358	}1359	mnt_drop_write(path->mnt);1360 1361out:1362	kvfree(xattr_list);1363	return err;1364}1365 1366int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path)1367{1368	char *name, *xattr_list = NULL;1369	ssize_t xattr_list_len;1370	int err = 0;1371 1372	xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);1373	if (xattr_list_len < 0) {1374		goto out;1375	} else if (!xattr_list_len) {1376		ksmbd_debug(SMB, "empty xattr in the file\n");1377		goto out;1378	}1379 1380	for (name = xattr_list; name - xattr_list < xattr_list_len;1381			name += strlen(name) + 1) {1382		ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));1383 1384		if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) {1385			err = ksmbd_vfs_remove_xattr(idmap, path, name, true);1386			if (err)1387				ksmbd_debug(SMB, "remove xattr failed : %s\n", name);1388		}1389	}1390out:1391	kvfree(xattr_list);1392	return err;1393}1394 1395static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *idmap,1396							    struct inode *inode,1397							    int acl_type)1398{1399	struct xattr_smb_acl *smb_acl = NULL;1400	struct posix_acl *posix_acls;1401	struct posix_acl_entry *pa_entry;1402	struct xattr_acl_entry *xa_entry;1403	int i;1404 1405	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))1406		return NULL;1407 1408	posix_acls = get_inode_acl(inode, acl_type);1409	if (IS_ERR_OR_NULL(posix_acls))1410		return NULL;1411 1412	smb_acl = kzalloc(sizeof(struct xattr_smb_acl) +1413			  sizeof(struct xattr_acl_entry) * posix_acls->a_count,1414			  GFP_KERNEL);1415	if (!smb_acl)1416		goto out;1417 1418	smb_acl->count = posix_acls->a_count;1419	pa_entry = posix_acls->a_entries;1420	xa_entry = smb_acl->entries;1421	for (i = 0; i < posix_acls->a_count; i++, pa_entry++, xa_entry++) {1422		switch (pa_entry->e_tag) {1423		case ACL_USER:1424			xa_entry->type = SMB_ACL_USER;1425			xa_entry->uid = posix_acl_uid_translate(idmap, pa_entry);1426			break;1427		case ACL_USER_OBJ:1428			xa_entry->type = SMB_ACL_USER_OBJ;1429			break;1430		case ACL_GROUP:1431			xa_entry->type = SMB_ACL_GROUP;1432			xa_entry->gid = posix_acl_gid_translate(idmap, pa_entry);1433			break;1434		case ACL_GROUP_OBJ:1435			xa_entry->type = SMB_ACL_GROUP_OBJ;1436			break;1437		case ACL_OTHER:1438			xa_entry->type = SMB_ACL_OTHER;1439			break;1440		case ACL_MASK:1441			xa_entry->type = SMB_ACL_MASK;1442			break;1443		default:1444			pr_err("unknown type : 0x%x\n", pa_entry->e_tag);1445			goto out;1446		}1447 1448		if (pa_entry->e_perm & ACL_READ)1449			xa_entry->perm |= SMB_ACL_READ;1450		if (pa_entry->e_perm & ACL_WRITE)1451			xa_entry->perm |= SMB_ACL_WRITE;1452		if (pa_entry->e_perm & ACL_EXECUTE)1453			xa_entry->perm |= SMB_ACL_EXECUTE;1454	}1455out:1456	posix_acl_release(posix_acls);1457	return smb_acl;1458}1459 1460int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,1461			   struct mnt_idmap *idmap,1462			   const struct path *path,1463			   struct smb_ntsd *pntsd, int len,1464			   bool get_write)1465{1466	int rc;1467	struct ndr sd_ndr = {0}, acl_ndr = {0};1468	struct xattr_ntacl acl = {0};1469	struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL;1470	struct dentry *dentry = path->dentry;1471	struct inode *inode = d_inode(dentry);1472 1473	acl.version = 4;1474	acl.hash_type = XATTR_SD_HASH_TYPE_SHA256;1475	acl.current_time = ksmbd_UnixTimeToNT(current_time(inode));1476 1477	memcpy(acl.desc, "posix_acl", 9);1478	acl.desc_len = 10;1479 1480	pntsd->osidoffset =1481		cpu_to_le32(le32_to_cpu(pntsd->osidoffset) + NDR_NTSD_OFFSETOF);1482	pntsd->gsidoffset =1483		cpu_to_le32(le32_to_cpu(pntsd->gsidoffset) + NDR_NTSD_OFFSETOF);1484	pntsd->dacloffset =1485		cpu_to_le32(le32_to_cpu(pntsd->dacloffset) + NDR_NTSD_OFFSETOF);1486 1487	acl.sd_buf = (char *)pntsd;1488	acl.sd_size = len;1489 1490	rc = ksmbd_gen_sd_hash(conn, acl.sd_buf, acl.sd_size, acl.hash);1491	if (rc) {1492		pr_err("failed to generate hash for ndr acl\n");1493		return rc;1494	}1495 1496	smb_acl = ksmbd_vfs_make_xattr_posix_acl(idmap, inode,1497						 ACL_TYPE_ACCESS);1498	if (S_ISDIR(inode->i_mode))1499		def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(idmap, inode,1500							     ACL_TYPE_DEFAULT);1501 1502	rc = ndr_encode_posix_acl(&acl_ndr, idmap, inode,1503				  smb_acl, def_smb_acl);1504	if (rc) {1505		pr_err("failed to encode ndr to posix acl\n");1506		goto out;1507	}1508 1509	rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset,1510			       acl.posix_acl_hash);1511	if (rc) {1512		pr_err("failed to generate hash for ndr acl\n");1513		goto out;1514	}1515 1516	rc = ndr_encode_v4_ntacl(&sd_ndr, &acl);1517	if (rc) {1518		pr_err("failed to encode ndr to posix acl\n");1519		goto out;1520	}1521 1522	rc = ksmbd_vfs_setxattr(idmap, path,1523				XATTR_NAME_SD, sd_ndr.data,1524				sd_ndr.offset, 0, get_write);1525	if (rc < 0)1526		pr_err("Failed to store XATTR ntacl :%d\n", rc);1527 1528	kfree(sd_ndr.data);1529out:1530	kfree(acl_ndr.data);1531	kfree(smb_acl);1532	kfree(def_smb_acl);1533	return rc;1534}1535 1536int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,1537			   struct mnt_idmap *idmap,1538			   struct dentry *dentry,1539			   struct smb_ntsd **pntsd)1540{1541	int rc;1542	struct ndr n;1543	struct inode *inode = d_inode(dentry);1544	struct ndr acl_ndr = {0};1545	struct xattr_ntacl acl;1546	struct xattr_smb_acl *smb_acl = NULL, *def_smb_acl = NULL;1547	__u8 cmp_hash[XATTR_SD_HASH_SIZE] = {0};1548 1549	rc = ksmbd_vfs_getxattr(idmap, dentry, XATTR_NAME_SD, &n.data);1550	if (rc <= 0)1551		return rc;1552 1553	n.length = rc;1554	rc = ndr_decode_v4_ntacl(&n, &acl);1555	if (rc)1556		goto free_n_data;1557 1558	smb_acl = ksmbd_vfs_make_xattr_posix_acl(idmap, inode,1559						 ACL_TYPE_ACCESS);1560	if (S_ISDIR(inode->i_mode))1561		def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(idmap, inode,1562							     ACL_TYPE_DEFAULT);1563 1564	rc = ndr_encode_posix_acl(&acl_ndr, idmap, inode, smb_acl,1565				  def_smb_acl);1566	if (rc) {1567		pr_err("failed to encode ndr to posix acl\n");1568		goto out_free;1569	}1570 1571	rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset, cmp_hash);1572	if (rc) {1573		pr_err("failed to generate hash for ndr acl\n");1574		goto out_free;1575	}1576 1577	if (memcmp(cmp_hash, acl.posix_acl_hash, XATTR_SD_HASH_SIZE)) {1578		pr_err("hash value diff\n");1579		rc = -EINVAL;1580		goto out_free;1581	}1582 1583	*pntsd = acl.sd_buf;1584	if (acl.sd_size < sizeof(struct smb_ntsd)) {1585		pr_err("sd size is invalid\n");1586		goto out_free;1587	}1588 1589	(*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) -1590					   NDR_NTSD_OFFSETOF);1591	(*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) -1592					   NDR_NTSD_OFFSETOF);1593	(*pntsd)->dacloffset = cpu_to_le32(le32_to_cpu((*pntsd)->dacloffset) -1594					   NDR_NTSD_OFFSETOF);1595 1596	rc = acl.sd_size;1597out_free:1598	kfree(acl_ndr.data);1599	kfree(smb_acl);1600	kfree(def_smb_acl);1601	if (rc < 0) {1602		kfree(acl.sd_buf);1603		*pntsd = NULL;1604	}1605 1606free_n_data:1607	kfree(n.data);1608	return rc;1609}1610 1611int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,1612				   const struct path *path,1613				   struct xattr_dos_attrib *da,1614				   bool get_write)1615{1616	struct ndr n;1617	int err;1618 1619	err = ndr_encode_dos_attr(&n, da);1620	if (err)1621		return err;1622 1623	err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE,1624				 (void *)n.data, n.offset, 0, get_write);1625	if (err)1626		ksmbd_debug(SMB, "failed to store dos attribute in xattr\n");1627	kfree(n.data);1628 1629	return err;1630}1631 1632int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap,1633				   struct dentry *dentry,1634				   struct xattr_dos_attrib *da)1635{1636	struct ndr n;1637	int err;1638 1639	err = ksmbd_vfs_getxattr(idmap, dentry, XATTR_NAME_DOS_ATTRIBUTE,1640				 (char **)&n.data);1641	if (err > 0) {1642		n.length = err;1643		if (ndr_decode_dos_attr(&n, da))1644			err = -EINVAL;1645		kfree(n.data);1646	} else {1647		ksmbd_debug(SMB, "failed to load dos attribute in xattr\n");1648	}1649 1650	return err;1651}1652 1653/**1654 * ksmbd_vfs_init_kstat() - convert unix stat information to smb stat format1655 * @p:          destination buffer1656 * @ksmbd_kstat:      ksmbd kstat wrapper1657 *1658 * Returns: pointer to the converted &struct file_directory_info1659 */1660void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat)1661{1662	struct file_directory_info *info = (struct file_directory_info *)(*p);1663	struct kstat *kstat = ksmbd_kstat->kstat;1664	u64 time;1665 1666	info->FileIndex = 0;1667	info->CreationTime = cpu_to_le64(ksmbd_kstat->create_time);1668	time = ksmbd_UnixTimeToNT(kstat->atime);1669	info->LastAccessTime = cpu_to_le64(time);1670	time = ksmbd_UnixTimeToNT(kstat->mtime);1671	info->LastWriteTime = cpu_to_le64(time);1672	time = ksmbd_UnixTimeToNT(kstat->ctime);1673	info->ChangeTime = cpu_to_le64(time);1674 1675	if (ksmbd_kstat->file_attributes & FILE_ATTRIBUTE_DIRECTORY_LE) {1676		info->EndOfFile = 0;1677		info->AllocationSize = 0;1678	} else {1679		info->EndOfFile = cpu_to_le64(kstat->size);1680		info->AllocationSize = cpu_to_le64(kstat->blocks << 9);1681	}1682	info->ExtFileAttributes = ksmbd_kstat->file_attributes;1683 1684	return info;1685}1686 1687int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,1688				struct mnt_idmap *idmap,1689				struct dentry *dentry,1690				struct ksmbd_kstat *ksmbd_kstat)1691{1692	struct ksmbd_share_config *share_conf = work->tcon->share_conf;1693	u64 time;1694	int rc;1695	struct path path = {1696		.mnt = share_conf->vfs_path.mnt,1697		.dentry = dentry,1698	};1699 1700	rc = vfs_getattr(&path, ksmbd_kstat->kstat,1701			 STATX_BASIC_STATS | STATX_BTIME,1702			 AT_STATX_SYNC_AS_STAT);1703	if (rc)1704		return rc;1705 1706	time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);1707	ksmbd_kstat->create_time = time;1708 1709	/*1710	 * set default value for the case that store dos attributes is not yes1711	 * or that acl is disable in server's filesystem and the config is yes.1712	 */1713	if (S_ISDIR(ksmbd_kstat->kstat->mode))1714		ksmbd_kstat->file_attributes = FILE_ATTRIBUTE_DIRECTORY_LE;1715	else1716		ksmbd_kstat->file_attributes = FILE_ATTRIBUTE_ARCHIVE_LE;1717 1718	if (test_share_config_flag(work->tcon->share_conf,1719				   KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) {1720		struct xattr_dos_attrib da;1721 1722		rc = ksmbd_vfs_get_dos_attrib_xattr(idmap, dentry, &da);1723		if (rc > 0) {1724			ksmbd_kstat->file_attributes = cpu_to_le32(da.attr);1725			ksmbd_kstat->create_time = da.create_time;1726		} else {1727			ksmbd_debug(VFS, "fail to load dos attribute.\n");1728		}1729	}1730 1731	return 0;1732}1733 1734ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,1735				struct dentry *dentry, char *attr_name,1736				int attr_name_len)1737{1738	char *name, *xattr_list = NULL;1739	ssize_t value_len = -ENOENT, xattr_list_len;1740 1741	xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list);1742	if (xattr_list_len <= 0)1743		goto out;1744 1745	for (name = xattr_list; name - xattr_list < xattr_list_len;1746			name += strlen(name) + 1) {1747		ksmbd_debug(VFS, "%s, len %zd\n", name, strlen(name));1748		if (strncasecmp(attr_name, name, attr_name_len))1749			continue;1750 1751		value_len = ksmbd_vfs_xattr_len(idmap, dentry, name);1752		break;1753	}1754 1755out:1756	kvfree(xattr_list);1757	return value_len;1758}1759 1760int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,1761				size_t *xattr_stream_name_size, int s_type)1762{1763	char *type, *buf;1764 1765	if (s_type == DIR_STREAM)1766		type = ":$INDEX_ALLOCATION";1767	else1768		type = ":$DATA";1769 1770	buf = kasprintf(GFP_KERNEL, "%s%s%s",1771			XATTR_NAME_STREAM, stream_name,	type);1772	if (!buf)1773		return -ENOMEM;1774 1775	*xattr_stream_name = buf;1776	*xattr_stream_name_size = strlen(buf) + 1;1777 1778	return 0;1779}1780 1781int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,1782			       struct ksmbd_file *src_fp,1783			       struct ksmbd_file *dst_fp,1784			       struct srv_copychunk *chunks,1785			       unsigned int chunk_count,1786			       unsigned int *chunk_count_written,1787			       unsigned int *chunk_size_written,1788			       loff_t *total_size_written)1789{1790	unsigned int i;1791	loff_t src_off, dst_off, src_file_size;1792	size_t len;1793	int ret;1794 1795	*chunk_count_written = 0;1796	*chunk_size_written = 0;1797	*total_size_written = 0;1798 1799	if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) {1800		pr_err("no right to read(%pD)\n", src_fp->filp);1801		return -EACCES;1802	}1803	if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) {1804		pr_err("no right to write(%pD)\n", dst_fp->filp);1805		return -EACCES;1806	}1807 1808	if (ksmbd_stream_fd(src_fp) || ksmbd_stream_fd(dst_fp))1809		return -EBADF;1810 1811	smb_break_all_levII_oplock(work, dst_fp, 1);1812 1813	if (!work->tcon->posix_extensions) {1814		for (i = 0; i < chunk_count; i++) {1815			src_off = le64_to_cpu(chunks[i].SourceOffset);1816			dst_off = le64_to_cpu(chunks[i].TargetOffset);1817			len = le32_to_cpu(chunks[i].Length);1818 1819			if (check_lock_range(src_fp->filp, src_off,1820					     src_off + len - 1, READ))1821				return -EAGAIN;1822			if (check_lock_range(dst_fp->filp, dst_off,1823					     dst_off + len - 1, WRITE))1824				return -EAGAIN;1825		}1826	}1827 1828	src_file_size = i_size_read(file_inode(src_fp->filp));1829 1830	for (i = 0; i < chunk_count; i++) {1831		src_off = le64_to_cpu(chunks[i].SourceOffset);1832		dst_off = le64_to_cpu(chunks[i].TargetOffset);1833		len = le32_to_cpu(chunks[i].Length);1834 1835		if (src_off + len > src_file_size)1836			return -E2BIG;1837 1838		ret = vfs_copy_file_range(src_fp->filp, src_off,1839					  dst_fp->filp, dst_off, len, 0);1840		if (ret == -EOPNOTSUPP || ret == -EXDEV)1841			ret = vfs_copy_file_range(src_fp->filp, src_off,1842						  dst_fp->filp, dst_off, len,1843						  COPY_FILE_SPLICE);1844		if (ret < 0)1845			return ret;1846 1847		*chunk_count_written += 1;1848		*total_size_written += ret;1849	}1850	return 0;1851}1852 1853void ksmbd_vfs_posix_lock_wait(struct file_lock *flock)1854{1855	wait_event(flock->c.flc_wait, !flock->c.flc_blocker);1856}1857 1858int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout)1859{1860	return wait_event_interruptible_timeout(flock->c.flc_wait,1861						!flock->c.flc_blocker,1862						timeout);1863}1864 1865void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock)1866{1867	locks_delete_block(flock);1868}1869 1870int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,1871				 struct path *path)1872{1873	struct posix_acl_state acl_state;1874	struct posix_acl *acls;1875	struct dentry *dentry = path->dentry;1876	struct inode *inode = d_inode(dentry);1877	int rc;1878 1879	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))1880		return -EOPNOTSUPP;1881 1882	ksmbd_debug(SMB, "Set posix acls\n");1883	rc = init_acl_state(&acl_state, 1);1884	if (rc)1885		return rc;1886 1887	/* Set default owner group */1888	acl_state.owner.allow = (inode->i_mode & 0700) >> 6;1889	acl_state.group.allow = (inode->i_mode & 0070) >> 3;1890	acl_state.other.allow = inode->i_mode & 0007;1891	acl_state.users->aces[acl_state.users->n].uid = inode->i_uid;1892	acl_state.users->aces[acl_state.users->n++].perms.allow =1893		acl_state.owner.allow;1894	acl_state.groups->aces[acl_state.groups->n].gid = inode->i_gid;1895	acl_state.groups->aces[acl_state.groups->n++].perms.allow =1896		acl_state.group.allow;1897	acl_state.mask.allow = 0x07;1898 1899	acls = posix_acl_alloc(6, GFP_KERNEL);1900	if (!acls) {1901		free_acl_state(&acl_state);1902		return -ENOMEM;1903	}1904	posix_state_to_acl(&acl_state, acls->a_entries);1905 1906	rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);1907	if (rc < 0)1908		ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",1909			    rc);1910	else if (S_ISDIR(inode->i_mode)) {1911		posix_state_to_acl(&acl_state, acls->a_entries);1912		rc = set_posix_acl(idmap, dentry, ACL_TYPE_DEFAULT, acls);1913		if (rc < 0)1914			ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",1915				    rc);1916	}1917 1918	free_acl_state(&acl_state);1919	posix_acl_release(acls);1920	return rc;1921}1922 1923int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,1924				struct path *path, struct inode *parent_inode)1925{1926	struct posix_acl *acls;1927	struct posix_acl_entry *pace;1928	struct dentry *dentry = path->dentry;1929	struct inode *inode = d_inode(dentry);1930	int rc, i;1931 1932	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))1933		return -EOPNOTSUPP;1934 1935	acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);1936	if (IS_ERR_OR_NULL(acls))1937		return -ENOENT;1938	pace = acls->a_entries;1939 1940	for (i = 0; i < acls->a_count; i++, pace++) {1941		if (pace->e_tag == ACL_MASK) {1942			pace->e_perm = 0x07;1943			break;1944		}1945	}1946 1947	rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);1948	if (rc < 0)1949		ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",1950			    rc);1951	if (S_ISDIR(inode->i_mode)) {1952		rc = set_posix_acl(idmap, dentry, ACL_TYPE_DEFAULT,1953				   acls);1954		if (rc < 0)1955			ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",1956				    rc);1957	}1958 1959	posix_acl_release(acls);1960	return rc;1961}1962