Commit 1f952675 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ntfs3 updates from Konstantin Komarov:

 - fix some memory leaks and panic

 - fixed xfstests (tested on x86_64): generic/092 generic/099
   generic/228 generic/240 generic/307 generic/444

 - fix some typos, dead code, etc

* tag 'ntfs3_for_5.19' of https://github.com/Paragon-Software-Group/linux-ntfs3:
  fs/ntfs3: provide block_invalidate_folio to fix memory leak
  fs/ntfs3: Fix invalid free in log_replay
  fs/ntfs3: Update valid size if -EIOCBQUEUED
  fs/ntfs3: Check new size for limits
  fs/ntfs3: Fix fiemap + fix shrink file size (to remove preallocated space)
  fs/ntfs3: In function ntfs_set_acl_ex do not change inode->i_mode if called from function ntfs_init_acl
  fs/ntfs3: Optimize locking in ntfs_save_wsl_perm
  fs/ntfs3: Update i_ctime when xattr is added
  fs/ntfs3: Restore ntfs_xattr_get_acl and ntfs_xattr_set_acl functions
  fs/ntfs3: Keep preallocated only if option prealloc enabled
  fs/ntfs3: Fix some memory leaks in an error handling path of 'log_replay()'
parents 67850b7b 724bbe49
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -492,7 +492,7 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)

	down_write(&ni->file.run_lock);
	err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, new_size,
			    &new_valid, true, NULL);
			    &new_valid, ni->mi.sbi->options->prealloc, NULL);
	up_write(&ni->file.run_lock);

	if (new_valid < ni->i_valid)
@@ -659,7 +659,13 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
		/*
		 * Normal file: Allocate clusters, do not change 'valid' size.
		 */
		err = ntfs_set_size(inode, max(end, i_size));
		loff_t new_size = max(end, i_size);

		err = inode_newsize_ok(inode, new_size);
		if (err)
			goto out;

		err = ntfs_set_size(inode, new_size);
		if (err)
			goto out;

@@ -759,7 +765,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
		}
		inode_dio_wait(inode);

		if (attr->ia_size < oldsize)
		if (attr->ia_size <= oldsize)
			err = ntfs_truncate(inode, attr->ia_size);
		else if (attr->ia_size > oldsize)
			err = ntfs_extend(inode, attr->ia_size, 0, NULL);
+7 −3
Original line number Diff line number Diff line
@@ -1964,10 +1964,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,

		vcn += clen;

		if (vbo + bytes >= end) {
		if (vbo + bytes >= end)
			bytes = end - vbo;
			flags |= FIEMAP_EXTENT_LAST;
		}

		if (vbo + bytes <= valid) {
			;
@@ -1977,6 +1975,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
			/* vbo < valid && valid < vbo + bytes */
			u64 dlen = valid - vbo;

			if (vbo + dlen >= end)
				flags |= FIEMAP_EXTENT_LAST;

			err = fiemap_fill_next_extent(fieinfo, vbo, lbo, dlen,
						      flags);
			if (err < 0)
@@ -1995,6 +1996,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
			flags |= FIEMAP_EXTENT_UNWRITTEN;
		}

		if (vbo + bytes >= end)
			flags |= FIEMAP_EXTENT_LAST;

		err = fiemap_fill_next_extent(fieinfo, vbo, lbo, bytes, flags);
		if (err < 0)
			break;
+7 −5
Original line number Diff line number Diff line
@@ -1185,8 +1185,6 @@ static int log_read_rst(struct ntfs_log *log, u32 l_size, bool first,
	if (!r_page)
		return -ENOMEM;

	memset(info, 0, sizeof(struct restart_info));

	/* Determine which restart area we are looking for. */
	if (first) {
		vbo = 0;
@@ -3791,10 +3789,11 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
	if (!log)
		return -ENOMEM;

	memset(&rst_info, 0, sizeof(struct restart_info));

	log->ni = ni;
	log->l_size = l_size;
	log->one_page_buf = kmalloc(page_size, GFP_NOFS);

	if (!log->one_page_buf) {
		err = -ENOMEM;
		goto out;
@@ -3842,6 +3841,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
	if (rst_info.vbo)
		goto check_restart_area;

	memset(&rst_info2, 0, sizeof(struct restart_info));
	err = log_read_rst(log, l_size, false, &rst_info2);

	/* Determine which restart area to use. */
@@ -4085,8 +4085,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
		if (client == LFS_NO_CLIENT_LE) {
			/* Insert "NTFS" client LogFile. */
			client = ra->client_idx[0];
			if (client == LFS_NO_CLIENT_LE)
				return -EINVAL;
			if (client == LFS_NO_CLIENT_LE) {
				err = -EINVAL;
				goto out;
			}

			t16 = le16_to_cpu(client);
			cr = ca + t16;
+7 −2
Original line number Diff line number Diff line
@@ -758,6 +758,7 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
	loff_t vbo = iocb->ki_pos;
	loff_t end;
	int wr = iov_iter_rw(iter) & WRITE;
	size_t iter_count = iov_iter_count(iter);
	loff_t valid;
	ssize_t ret;

@@ -771,10 +772,13 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
				 wr ? ntfs_get_block_direct_IO_W
				    : ntfs_get_block_direct_IO_R);

	if (ret <= 0)
	if (ret > 0)
		end = vbo + ret;
	else if (wr && ret == -EIOCBQUEUED)
		end = vbo + iter_count;
	else
		goto out;

	end = vbo + ret;
	valid = ni->i_valid;
	if (wr) {
		if (end > valid && !S_ISBLK(inode->i_mode)) {
@@ -1950,6 +1954,7 @@ const struct address_space_operations ntfs_aops = {
	.direct_IO	= ntfs_direct_IO,
	.bmap		= ntfs_bmap,
	.dirty_folio	= block_dirty_folio,
	.invalidate_folio = block_invalidate_folio,
};

const struct address_space_operations ntfs_aops_cmpr = {
+119 −17
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
		return -ENOMEM;

	if (!size) {
		;
		/* EA info persists, but xattr is empty. Looks like EA problem. */
	} else if (attr_ea->non_res) {
		struct runs_tree run;

@@ -259,7 +259,7 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len,

static noinline int ntfs_set_ea(struct inode *inode, const char *name,
				size_t name_len, const void *value,
				size_t val_size, int flags)
				size_t val_size, int flags, bool locked)
{
	struct ntfs_inode *ni = ntfs_i(inode);
	struct ntfs_sb_info *sbi = ni->mi.sbi;
@@ -278,6 +278,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
	u64 new_sz;
	void *p;

	if (!locked)
		ni_lock(ni);

	run_init(&ea_run);
@@ -467,6 +468,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
	mark_inode_dirty(&ni->vfs_inode);

out:
	if (!locked)
		ni_unlock(ni);

	run_close(&ea_run);
@@ -541,7 +543,7 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)

static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
				    struct inode *inode, struct posix_acl *acl,
				    int type)
				    int type, bool init_acl)
{
	const char *name;
	size_t size, name_len;
@@ -554,8 +556,9 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,

	switch (type) {
	case ACL_TYPE_ACCESS:
		if (acl) {
			umode_t mode = inode->i_mode;
		/* Do not change i_mode if we are in init_acl */
		if (acl && !init_acl) {
			umode_t mode;

			err = posix_acl_update_mode(mnt_userns, inode, &mode,
						    &acl);
@@ -598,7 +601,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
		flags = 0;
	}

	err = ntfs_set_ea(inode, name, name_len, value, size, flags);
	err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
	if (err == -ENODATA && !size)
		err = 0; /* Removing non existed xattr. */
	if (!err)
@@ -616,7 +619,68 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
		 struct posix_acl *acl, int type)
{
	return ntfs_set_acl_ex(mnt_userns, inode, acl, type);
	return ntfs_set_acl_ex(mnt_userns, inode, acl, type, false);
}

static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
			      struct inode *inode, int type, void *buffer,
			      size_t size)
{
	struct posix_acl *acl;
	int err;

	if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
		ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
		return -EOPNOTSUPP;
	}

	acl = ntfs_get_acl(inode, type, false);
	if (IS_ERR(acl))
		return PTR_ERR(acl);

	if (!acl)
		return -ENODATA;

	err = posix_acl_to_xattr(mnt_userns, acl, buffer, size);
	posix_acl_release(acl);

	return err;
}

static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
			      struct inode *inode, int type, const void *value,
			      size_t size)
{
	struct posix_acl *acl;
	int err;

	if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
		ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
		return -EOPNOTSUPP;
	}

	if (!inode_owner_or_capable(mnt_userns, inode))
		return -EPERM;

	if (!value) {
		acl = NULL;
	} else {
		acl = posix_acl_from_xattr(mnt_userns, value, size);
		if (IS_ERR(acl))
			return PTR_ERR(acl);

		if (acl) {
			err = posix_acl_valid(mnt_userns, acl);
			if (err)
				goto release_and_out;
		}
	}

	err = ntfs_set_acl(mnt_userns, inode, acl, type);

release_and_out:
	posix_acl_release(acl);
	return err;
}

/*
@@ -636,7 +700,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,

	if (default_acl) {
		err = ntfs_set_acl_ex(mnt_userns, inode, default_acl,
				      ACL_TYPE_DEFAULT);
				      ACL_TYPE_DEFAULT, true);
		posix_acl_release(default_acl);
	} else {
		inode->i_default_acl = NULL;
@@ -647,7 +711,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
	else {
		if (!err)
			err = ntfs_set_acl_ex(mnt_userns, inode, acl,
					      ACL_TYPE_ACCESS);
					      ACL_TYPE_ACCESS, true);
		posix_acl_release(acl);
	}

@@ -785,6 +849,23 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
		goto out;
	}

#ifdef CONFIG_NTFS3_FS_POSIX_ACL
	if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
	     !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
		     sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
	    (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
	     !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
		     sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
		/* TODO: init_user_ns? */
		err = ntfs_xattr_get_acl(
			&init_user_ns, inode,
			name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
				? ACL_TYPE_ACCESS
				: ACL_TYPE_DEFAULT,
			buffer, size);
		goto out;
	}
#endif
	/* Deal with NTFS extended attribute. */
	err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);

@@ -897,10 +978,29 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
		goto out;
	}

#ifdef CONFIG_NTFS3_FS_POSIX_ACL
	if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
	     !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
		     sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
	    (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
	     !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
		     sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
		err = ntfs_xattr_set_acl(
			mnt_userns, inode,
			name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
				? ACL_TYPE_ACCESS
				: ACL_TYPE_DEFAULT,
			value, size);
		goto out;
	}
#endif
	/* Deal with NTFS extended attribute. */
	err = ntfs_set_ea(inode, name, name_len, value, size, flags);
	err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);

out:
	inode->i_ctime = current_time(inode);
	mark_inode_dirty(inode);

	return err;
}

@@ -913,35 +1013,37 @@ int ntfs_save_wsl_perm(struct inode *inode)
{
	int err;
	__le32 value;
	struct ntfs_inode *ni = ntfs_i(inode);

	/* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */
	ni_lock(ni);
	value = cpu_to_le32(i_uid_read(inode));
	err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
			  sizeof(value), 0);
			  sizeof(value), 0, true); /* true == already locked. */
	if (err)
		goto out;

	value = cpu_to_le32(i_gid_read(inode));
	err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
			  sizeof(value), 0);
			  sizeof(value), 0, true);
	if (err)
		goto out;

	value = cpu_to_le32(inode->i_mode);
	err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
			  sizeof(value), 0);
			  sizeof(value), 0, true);
	if (err)
		goto out;

	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
		value = cpu_to_le32(inode->i_rdev);
		err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
				  sizeof(value), 0);
				  sizeof(value), 0, true);
		if (err)
			goto out;
	}

out:
	ni_unlock(ni);
	/* In case of error should we delete all WSL xattr? */
	return err;
}