Commit 68353984 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '5.6-smb3-fixes-and-dfs-and-readdir-improvements' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs updates from Steve French:
 "Various SMB3/CIFS fixes including four for stable.

   - Improvement to fallocate (enables 3 additional xfstests)

   - Fix for file creation when mounting with modefromsid

   - Add ability to backup/restore dos attributes and creation time

   - DFS failover and reconnect fixes

   - performance optimization for readir

  Note that due to the upcoming SMB3 Test Event (at SNIA SDC next week)
  there will likely be more changesets near the end of the merge window
  (since we will be testing heavily next week, I held off on some
  patches and I expect some additional multichannel patches as well as
  patches to enable some additional xfstests)"

* tag '5.6-smb3-fixes-and-dfs-and-readdir-improvements' of git://git.samba.org/sfrench/cifs-2.6: (24 commits)
  CIFS: Fix task struct use-after-free on reconnect
  cifs: use PTR_ERR_OR_ZERO() to simplify code
  cifs: add support for fallocate mode 0 for non-sparse files
  cifs: fix NULL dereference in match_prepath
  smb3: fix default permissions on new files when mounting with modefromsid
  CIFS: Add support for setting owner info, dos attributes, and create time
  cifs: remove set but not used variable 'server'
  cifs: Fix memory allocation in __smb2_handle_cancelled_cmd()
  cifs: Fix mount options set in automount
  cifs: fix unitialized variable poential problem with network I/O cache lock patch
  cifs: Fix return value in __update_cache_entry
  cifs: Avoid doing network I/O while holding cache lock
  cifs: Fix potential deadlock when updating vol in cifs_reconnect()
  cifs: Merge is_path_valid() into get_normalized_path()
  cifs: Introduce helpers for finding TCP connection
  cifs: Get rid of kstrdup_const()'d paths
  cifs: Clean up DFS referral cache
  cifs: Don't use iov_iter::type directly
  cifs: set correct max-buffer-size for smb2_ioctl_init()
  cifs: use compounding for open and first query-dir for readdir()
  ...
parents c8994374 f1f27ad7
Loading
Loading
Loading
Loading
+43 −54
Original line number Original line Diff line number Diff line
@@ -120,17 +120,17 @@ cifs_build_devname(char *nodename, const char *prepath)




/**
/**
 * cifs_compose_mount_options	-	creates mount options for refferral
 * cifs_compose_mount_options	-	creates mount options for referral
 * @sb_mountdata:	parent/root DFS mount options (template)
 * @sb_mountdata:	parent/root DFS mount options (template)
 * @fullpath:		full path in UNC format
 * @fullpath:		full path in UNC format
 * @ref:		server's referral
 * @ref:		optional server's referral
 * @devname:		optional pointer for saving device name
 * @devname:		optional pointer for saving device name
 *
 *
 * creates mount options for submount based on template options sb_mountdata
 * creates mount options for submount based on template options sb_mountdata
 * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
 * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
 *
 *
 * Returns: pointer to new mount options or ERR_PTR.
 * Returns: pointer to new mount options or ERR_PTR.
 * Caller is responcible for freeing retunrned value if it is not error.
 * Caller is responsible for freeing returned value if it is not error.
 */
 */
char *cifs_compose_mount_options(const char *sb_mountdata,
char *cifs_compose_mount_options(const char *sb_mountdata,
				   const char *fullpath,
				   const char *fullpath,
@@ -150,6 +150,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
	if (sb_mountdata == NULL)
	if (sb_mountdata == NULL)
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);


	if (ref) {
		if (strlen(fullpath) - ref->path_consumed) {
		if (strlen(fullpath) - ref->path_consumed) {
			prepath = fullpath + ref->path_consumed;
			prepath = fullpath + ref->path_consumed;
			/* skip initial delimiter */
			/* skip initial delimiter */
@@ -163,6 +164,14 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
			name = NULL;
			name = NULL;
			goto compose_mount_options_err;
			goto compose_mount_options_err;
		}
		}
	} else {
		name = cifs_build_devname((char *)fullpath, NULL);
		if (IS_ERR(name)) {
			rc = PTR_ERR(name);
			name = NULL;
			goto compose_mount_options_err;
		}
	}


	rc = dns_resolve_server_name_to_ip(name, &srvIP);
	rc = dns_resolve_server_name_to_ip(name, &srvIP);
	if (rc < 0) {
	if (rc < 0) {
@@ -225,6 +234,8 @@ char *cifs_compose_mount_options(const char *sb_mountdata,


	if (devname)
	if (devname)
		*devname = name;
		*devname = name;
	else
		kfree(name);


	/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
	/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
	/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
	/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
@@ -241,23 +252,23 @@ compose_mount_options_err:
}
}


/**
/**
 * cifs_dfs_do_refmount - mounts specified path using provided refferal
 * cifs_dfs_do_mount - mounts specified path using DFS full path
 *
 * Always pass down @fullpath to smb3_do_mount() so we can use the root server
 * to perform failover in case we failed to connect to the first target in the
 * referral.
 *
 * @cifs_sb:		parent/root superblock
 * @cifs_sb:		parent/root superblock
 * @fullpath:		full path in UNC format
 * @fullpath:		full path in UNC format
 * @ref:		server's referral
 */
 */
static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
					  struct cifs_sb_info *cifs_sb,
					  struct cifs_sb_info *cifs_sb,
		const char *fullpath, const struct dfs_info3_param *ref)
					  const char *fullpath)
{
{
	struct vfsmount *mnt;
	struct vfsmount *mnt;
	char *mountdata;
	char *mountdata;
	char *devname;
	char *devname;


	/*
	 * Always pass down the DFS full path to smb3_do_mount() so we
	 * can use it later for failover.
	 */
	devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
	devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
	if (!devname)
	if (!devname)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);
@@ -266,7 +277,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,


	/* strip first '\' from fullpath */
	/* strip first '\' from fullpath */
	mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
	mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
					       fullpath + 1, ref, NULL);
					       fullpath + 1, NULL, NULL);
	if (IS_ERR(mountdata)) {
	if (IS_ERR(mountdata)) {
		kfree(devname);
		kfree(devname);
		return (struct vfsmount *)mountdata;
		return (struct vfsmount *)mountdata;
@@ -278,28 +289,16 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
	return mnt;
	return mnt;
}
}


static void dump_referral(const struct dfs_info3_param *ref)
{
	cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name);
	cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name);
	cifs_dbg(FYI, "DFS: fl: %d, srv_type: %d\n",
		 ref->flags, ref->server_type);
	cifs_dbg(FYI, "DFS: ref_flags: %d, path_consumed: %d\n",
		 ref->ref_flag, ref->path_consumed);
}

/*
/*
 * Create a vfsmount that we can automount
 * Create a vfsmount that we can automount
 */
 */
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
{
{
	struct dfs_info3_param referral = {0};
	struct cifs_sb_info *cifs_sb;
	struct cifs_sb_info *cifs_sb;
	struct cifs_ses *ses;
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
	struct cifs_tcon *tcon;
	char *full_path, *root_path;
	char *full_path, *root_path;
	unsigned int xid;
	unsigned int xid;
	int len;
	int rc;
	int rc;
	struct vfsmount *mnt;
	struct vfsmount *mnt;


@@ -357,7 +356,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
	if (!rc) {
	if (!rc) {
		rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
		rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
				    cifs_remap(cifs_sb), full_path + 1,
				    cifs_remap(cifs_sb), full_path + 1,
				    &referral, NULL);
				    NULL, NULL);
	}
	}


	free_xid(xid);
	free_xid(xid);
@@ -366,26 +365,16 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
		mnt = ERR_PTR(rc);
		mnt = ERR_PTR(rc);
		goto free_root_path;
		goto free_root_path;
	}
	}

	dump_referral(&referral);

	len = strlen(referral.node_name);
	if (len < 2) {
		cifs_dbg(VFS, "%s: Net Address path too short: %s\n",
			 __func__, referral.node_name);
		mnt = ERR_PTR(-EINVAL);
		goto free_dfs_ref;
	}
	/*
	/*
	 * cifs_mount() will retry every available node server in case
	 * OK - we were able to get and cache a referral for @full_path.
	 * of failures.
	 *
	 * Now, pass it down to cifs_mount() and it will retry every available
	 * node server in case of failures - no need to do it here.
	 */
	 */
	mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, full_path, &referral);
	mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
	cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__,
	cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__,
		 referral.node_name, mnt);
		 full_path + 1, mnt);


free_dfs_ref:
	free_dfs_info_param(&referral);
free_root_path:
free_root_path:
	kfree(root_path);
	kfree(root_path);
free_full_path:
free_full_path:
+20 −0
Original line number Original line Diff line number Diff line
@@ -802,6 +802,26 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
	return;
	return;
}
}


unsigned int setup_authusers_ACE(struct cifs_ace *pntace)
{
	int i;
	unsigned int ace_size = 20;

	pntace->type = ACCESS_ALLOWED_ACE_TYPE;
	pntace->flags = 0x0;
	pntace->access_req = cpu_to_le32(GENERIC_ALL);
	pntace->sid.num_subauth = 1;
	pntace->sid.revision = 1;
	for (i = 0; i < NUM_AUTHS; i++)
		pntace->sid.authority[i] =  sid_authusers.authority[i];

	pntace->sid.sub_auth[0] =  sid_authusers.sub_auth[0];

	/* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
	pntace->size = cpu_to_le16(ace_size);
	return ace_size;
}

/*
/*
 * Fill in the special SID based on the mode. See
 * Fill in the special SID based on the mode. See
 * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
 * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+3 −0
Original line number Original line Diff line number Diff line
@@ -149,6 +149,9 @@ extern ssize_t cifs_file_copychunk_range(unsigned int xid,
					size_t len, unsigned int flags);
					size_t len, unsigned int flags);


extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern void cifs_setsize(struct inode *inode, loff_t offset);
extern int cifs_truncate_page(struct address_space *mapping, loff_t from);

#ifdef CONFIG_CIFS_NFSD_EXPORT
#ifdef CONFIG_CIFS_NFSD_EXPORT
extern const struct export_operations cifs_export_ops;
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
#endif /* CONFIG_CIFS_NFSD_EXPORT */
+1 −0
Original line number Original line Diff line number Diff line
@@ -1588,6 +1588,7 @@ struct mid_q_entry {
	mid_callback_t *callback; /* call completion callback */
	mid_callback_t *callback; /* call completion callback */
	mid_handle_t *handle; /* call handle mid callback */
	mid_handle_t *handle; /* call handle mid callback */
	void *callback_data;	  /* general purpose pointer for callback */
	void *callback_data;	  /* general purpose pointer for callback */
	struct task_struct *creator;
	void *resp_buf;		/* pointer to received SMB header */
	void *resp_buf;		/* pointer to received SMB header */
	unsigned int resp_buf_size;
	unsigned int resp_buf_size;
	int mid_state;	/* wish this were enum but can not pass to wait_event */
	int mid_state;	/* wish this were enum but can not pass to wait_event */
+4 −0
Original line number Original line Diff line number Diff line
@@ -213,6 +213,7 @@ extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
						const struct cifs_fid *, u32 *);
						const struct cifs_fid *, u32 *);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
				const char *, int);
				const char *, int);
extern unsigned int setup_authusers_ACE(struct cifs_ace *pace);
extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode);
extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode);


extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
@@ -596,6 +597,9 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);


void extract_unc_hostname(const char *unc, const char **h, size_t *len);
void extract_unc_hostname(const char *unc, const char **h, size_t *len);
int copy_path_name(char *dst, const char *src);
int copy_path_name(char *dst, const char *src);
int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
			       int resp_buftype,
			       struct cifs_search_info *srch_inf);


#ifdef CONFIG_CIFS_DFS_UPCALL
#ifdef CONFIG_CIFS_DFS_UPCALL
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
Loading