Unverified Commit 2b108260 authored by Konstantin Komarov's avatar Konstantin Komarov
Browse files

fs/ntfs3: atomic_open implementation



Added ntfs_atomic_open function.
Relaxed locking in ntfs_create_inode.

Signed-off-by: default avatarKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
parent 07f4aa9d
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -1184,6 +1184,18 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
	return ERR_PTR(err);
}

/*
 * ntfs_create_inode
 *
 * Helper function for:
 * - ntfs_create
 * - ntfs_mknod
 * - ntfs_symlink
 * - ntfs_mkdir
 * - ntfs_atomic_open
 * 
 * NOTE: if fnd != NULL (ntfs_atomic_open) then @dir is locked
 */
struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
				struct inode *dir, struct dentry *dentry,
				const struct cpu_str *uni, umode_t mode,
@@ -1213,6 +1225,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
	struct REPARSE_DATA_BUFFER *rp = NULL;
	bool rp_inserted = false;

	if (!fnd)
		ni_lock_dir(dir_ni);

	dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
@@ -1583,6 +1596,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
		goto out6;

	/* Unlock parent directory before ntfs_init_acl. */
	if (!fnd)
		ni_unlock(dir_ni);

	inode->i_generation = le16_to_cpu(rec->seq);
@@ -1643,6 +1657,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
out7:

	/* Undo 'indx_insert_entry'. */
	if (!fnd)
		ni_lock_dir(dir_ni);
	indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
			  le16_to_cpu(new_de->key_size), sbi);
@@ -1671,6 +1686,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,

out1:
	if (err) {
		if (!fnd)
			ni_unlock(dir_ni);
		return ERR_PTR(err);
	}
+100 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/ctype.h>
#include <linux/posix_acl.h>

#include "debug.h"
#include "ntfs.h"
@@ -334,6 +335,104 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
	return err;
}

/*
 * ntfs_atomic_open
 *
 * inode_operations::atomic_open
 */
static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
			    struct file *file, u32 flags, umode_t mode)
{
	int err;
	struct inode *inode;
	struct ntfs_fnd *fnd = NULL;
	struct ntfs_inode *ni = ntfs_i(dir);
	struct dentry *d = NULL;
	struct cpu_str *uni = __getname();
	bool locked = false;

	if (!uni)
		return -ENOMEM;

	err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name,
				dentry->d_name.len, uni, NTFS_NAME_LEN,
				UTF16_HOST_ENDIAN);
	if (err < 0)
		goto out;

#ifdef CONFIG_NTFS3_FS_POSIX_ACL
	if (IS_POSIXACL(dir)) {
		/* 
		 * Load in cache current acl to avoid ni_lock(dir):
		 * ntfs_create_inode -> ntfs_init_acl -> posix_acl_create ->
		 * ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock
		 */
		struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT);

		if (IS_ERR(p)) {
			err = PTR_ERR(p);
			goto out;
		}
		posix_acl_release(p);
	}
#endif

	if (d_in_lookup(dentry)) {
		ni_lock_dir(ni);
		locked = true;
		fnd = fnd_get();
		if (!fnd) {
			err = -ENOMEM;
			goto out1;
		}

		d = d_splice_alias(dir_search_u(dir, uni, fnd), dentry);
		if (IS_ERR(d)) {
			err = PTR_ERR(d);
			d = NULL;
			goto out2;
		}

		if (d)
			dentry = d;
	}

	if (!(flags & O_CREAT) || d_really_is_positive(dentry)) {
		err = finish_no_open(file, d);
		goto out2;
	}

	file->f_mode |= FMODE_CREATED;

	/*
	 * fnd contains tree's path to insert to.
	 * If fnd is not NULL then dir is locked.
	 */

	/*
	 * Unfortunately I don't know how to get here correct 'struct nameidata *nd'
	 * or 'struct user_namespace *mnt_userns'.
	 * See atomic_open in fs/namei.c.
	 * This is why xfstest/633 failed.
	 * Looks like ntfs_atomic_open must accept 'struct user_namespace *mnt_userns' as argument.
	 */

	inode = ntfs_create_inode(&init_user_ns, dir, dentry, uni, mode, 0,
				  NULL, 0, fnd);
	err = IS_ERR(inode) ? PTR_ERR(inode)
			    : finish_open(file, dentry, ntfs_file_open);
	dput(d);

out2:
	fnd_put(fnd);
out1:
	if (locked)
		ni_unlock(ni);
out:
	__putname(uni);
	return err;
}

struct dentry *ntfs3_get_parent(struct dentry *child)
{
	struct inode *inode = d_inode(child);
@@ -500,6 +599,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
	.setattr	= ntfs3_setattr,
	.getattr	= ntfs_getattr,
	.listxattr	= ntfs_listxattr,
	.atomic_open	= ntfs_atomic_open,
	.fiemap		= ntfs_fiemap,
};