Commit 62e02084 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

smb: client: set ATTR_TEMPORARY with O_TMPFILE | O_EXCL



Set ATTR_TEMPORARY attribute on temporary delete-on-close files when
O_EXCL is specified in conjunction with O_TMPFILE to let some servers
cache as much data as possible and possibly never persist them into
storage, thereby improving performance.

Signed-off-by: default avatarPaulo Alcantara (Red Hat) <pc@manguebit.org>
Cc: David Howells <dhowells@redhat.com>
Cc: linux-cifs@vger.kernel.org
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 3e7d6303
Loading
Loading
Loading
Loading
+19 −26
Original line number Diff line number Diff line
@@ -1014,28 +1014,21 @@ static int cifs_ci_compare(const struct dentry *dentry,
	return 0;
}

static int set_hidden_attr(const unsigned int xid,
			   struct TCP_Server_Info *server,
			   struct file *file)
static int set_tmpfile_attr(const unsigned int xid, unsigned int oflags,
			    struct inode *inode, const char *full_path,
			    struct TCP_Server_Info *server)
{
	struct dentry *dentry = file->f_path.dentry;
	struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
	FILE_BASIC_INFO fi = {
		.Attributes = cpu_to_le32(cinode->cifsAttrs |
					  ATTR_HIDDEN),
	};
	void *page = alloc_dentry_path();
	const char *full_path;
	int rc;
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	FILE_BASIC_INFO fi;

	full_path = build_path_from_dentry(dentry, page);
	if (IS_ERR(full_path))
		rc = PTR_ERR(full_path);
	else
		rc =  server->ops->set_file_info(d_inode(dentry),
						 full_path, &fi, xid);
	free_dentry_path(page);
	return rc;
	cinode->cifsAttrs |= ATTR_HIDDEN;
	if (oflags & O_EXCL)
		cinode->cifsAttrs |= ATTR_TEMPORARY;

	fi = (FILE_BASIC_INFO) {
		.Attributes = cpu_to_le32(cinode->cifsAttrs),
	};
	return server->ops->set_file_info(inode, full_path, &fi, xid);
}

/*
@@ -1049,6 +1042,8 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
{
	struct dentry *dentry = file->f_path.dentry;
	struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
	char *path __free(kfree) = NULL, *name;
	unsigned int oflags = file->f_flags;
	size_t size = CIFS_TMPNAME_LEN + 1;
	int retries = 0, max_retries = 16;
	struct TCP_Server_Info *server;
@@ -1059,7 +1054,6 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
	struct cifs_tcon *tcon;
	unsigned int sbflags;
	struct inode *inode;
	char *path, *name;
	unsigned int xid;
	__u32 oplock;
	int rc;
@@ -1089,6 +1083,7 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
	if (IS_ERR(path)) {
		cifs_del_pending_open(&open);
		rc = PTR_ERR(path);
		path = NULL;
		goto out;
	}

@@ -1098,9 +1093,8 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
			  CIFS_TMPNAME_PREFIX "%0*x",
			  CIFS_TMPNAME_COUNTER_LEN,
			  atomic_inc_return(&cifs_tmpcounter));
		rc = __cifs_do_create(dir, dentry, path, xid, tlink,
				      file->f_flags, mode, &oplock,
				      &fid, NULL, &inode);
		rc = __cifs_do_create(dir, dentry, path, xid, tlink, oflags,
				      mode, &oplock, &fid, NULL, &inode);
		if (!rc) {
			set_nlink(inode, 0);
			mark_inode_dirty(inode);
@@ -1110,7 +1104,6 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
		}
	} while (unlikely(rc == -EEXIST) && ++retries < max_retries);

	kfree(path);
	if (rc) {
		cifs_del_pending_open(&open);
		goto out;
@@ -1134,7 +1127,7 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
		goto err_open;
	}

	rc = set_hidden_attr(xid, server, file);
	rc = set_tmpfile_attr(xid, oflags, inode, path, server);
	if (rc)
		goto out;

+17 −13
Original line number Diff line number Diff line
@@ -1237,6 +1237,20 @@ int smb2_rename_path(const unsigned int xid,
	return rc;
}

static int clear_tmpfile_attr(const unsigned int xid, struct cifs_tcon *tcon,
			      struct inode *inode, const char *full_path)
{
	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	FILE_BASIC_INFO fi;

	cinode->cifsAttrs &= ~(ATTR_TEMPORARY | ATTR_HIDDEN);
	fi = (FILE_BASIC_INFO) {
		.Attributes = cpu_to_le32(cinode->cifsAttrs),
	};
	return server->ops->set_file_info(inode, full_path, &fi, xid);
}

int smb2_create_hardlink(const unsigned int xid,
			 struct cifs_tcon *tcon,
			 struct dentry *source_dentry,
@@ -1246,24 +1260,14 @@ int smb2_create_hardlink(const unsigned int xid,
	struct inode *inode = source_dentry ? d_inode(source_dentry) : NULL;
	__u32 co = file_create_options(source_dentry);
	struct cifsFileInfo *cfile;

	if (inode) {
		struct cifsInodeInfo *cinode = CIFS_I(inode);
		FILE_BASIC_INFO fi;
		__le32 attrs;
	int rc;

		if (!test_bit(CIFS_INO_TMPFILE, &CIFS_I(inode)->flags))
			goto out;

		attrs = cpu_to_le32(cinode->cifsAttrs & ~ATTR_HIDDEN);
		fi = (FILE_BASIC_INFO){ .Attributes = attrs, };
		rc = smb2_set_file_info(inode, from_name, &fi, xid);
	if (inode && test_bit(CIFS_INO_TMPFILE, &CIFS_I(inode)->flags)) {
		rc = clear_tmpfile_attr(xid, tcon, inode, from_name);
		if (rc)
			return rc;
	}

out:
	cifs_get_writable_path(tcon, from_name, inode,
			       FIND_WITH_DELETE, &cfile);
	return smb2_set_path_attr(xid, tcon, from_name, to_name,