diff mbox

[02/45] CIFS: Simpliify cifs_mkdir call

Message ID 1342626541-29872-3-git-send-email-pshilovsky@samba.org (mailing list archive)
State New, archived
Headers show

Commit Message

Pavel Shilovsky July 18, 2012, 3:48 p.m. UTC
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
 fs/cifs/cifsproto.h |    4 +-
 fs/cifs/cifssmb.c   |    8 +-
 fs/cifs/inode.c     |  295 ++++++++++++++++++++++++++++-----------------------
 3 files changed, 167 insertions(+), 140 deletions(-)

Comments

Jeff Layton Aug. 1, 2012, 7:39 p.m. UTC | #1
On Wed, 18 Jul 2012 19:48:18 +0400
Pavel Shilovsky <pshilovsky@samba.org> wrote:

> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
> ---
>  fs/cifs/cifsproto.h |    4 +-
>  fs/cifs/cifssmb.c   |    8 +-
>  fs/cifs/inode.c     |  295 ++++++++++++++++++++++++++++-----------------------
>  3 files changed, 167 insertions(+), 140 deletions(-)
> 
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 5aadeec..51fbdf2 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -289,10 +289,10 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
>  				  u16 fid, u32 pid_of_opener);
>  
>  extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
> -				  struct cifs_tcon *tcon, char *file_name,
> +				  struct cifs_tcon *tcon, const char *file_name,
>  				  const struct cifs_unix_set_info_args *args,
>  				  const struct nls_table *nls_codepage,
> -				  int remap_special_chars);
> +				  int remap);
>  
>  extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
>  			const char *newName,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 846b803..ed472aa 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -5945,7 +5945,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
>  
>  int
>  CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
> -		       char *fileName,
> +		       const char *file_name,
>  		       const struct cifs_unix_set_info_args *args,
>  		       const struct nls_table *nls_codepage, int remap)
>  {
> @@ -5966,14 +5966,14 @@ setPermsRetry:
>  
>  	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
>  		name_len =
> -		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
> +		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
>  				       PATH_MAX, nls_codepage, remap);
>  		name_len++;	/* trailing null */
>  		name_len *= 2;
>  	} else {	/* BB improve the check for buffer overruns BB */
> -		name_len = strnlen(fileName, PATH_MAX);
> +		name_len = strnlen(file_name, PATH_MAX);
>  		name_len++;	/* trailing null */
> -		strncpy(pSMB->FileName, fileName, name_len);
> +		strncpy(pSMB->FileName, file_name, name_len);
>  	}
>  
>  	params = 6 + name_len;
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 35cb6a3..e9ba1a1 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -1219,16 +1219,165 @@ unlink_out:
>  	return rc;
>  }
>  
> +static int
> +cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
> +		 const char *full_path, struct cifs_sb_info *cifs_sb,
> +		 struct cifs_tcon *tcon, const unsigned int xid)
> +{
> +	int rc = 0;
> +	struct inode *newinode = NULL;
> +
> +	if (tcon->unix_ext)
> +		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
> +					      xid);
> +	else
> +		rc = cifs_get_inode_info(&newinode, full_path, NULL,
> +					 inode->i_sb, xid, NULL);
> +	if (rc)
> +		return rc;
> +
> +	d_instantiate(dentry, newinode);
> +	/*
> +	 * setting nlink not necessary except in cases where we failed to get it
> +	 * from the server or was set bogus
> +	 */
> +	if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
> +		set_nlink(dentry->d_inode, 2);
> +
> +	mode &= ~current_umask();
> +	/* must turn on setgid bit if parent dir has it */
> +	if (inode->i_mode & S_ISGID)
> +		mode |= S_ISGID;
> +
> +	if (tcon->unix_ext) {
> +		struct cifs_unix_set_info_args args = {
> +			.mode	= mode,
> +			.ctime	= NO_CHANGE_64,
> +			.atime	= NO_CHANGE_64,
> +			.mtime	= NO_CHANGE_64,
> +			.device	= 0,
> +		};
> +		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
> +			args.uid = (__u64)current_fsuid();
> +			if (inode->i_mode & S_ISGID)
> +				args.gid = (__u64)inode->i_gid;
> +			else
> +				args.gid = (__u64)current_fsgid();
> +		} else {
> +			args.uid = NO_CHANGE_64;
> +			args.gid = NO_CHANGE_64;
> +		}
> +		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
> +				       cifs_sb->local_nls,
> +				       cifs_sb->mnt_cifs_flags &
> +				       CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	} else {
> +		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
> +		    (mode & S_IWUGO) == 0) {
> +			FILE_BASIC_INFO info;
> +			struct cifsInodeInfo *cifsInode;
> +			u32 dosattrs;
> +			int tmprc;
> +
> +			memset(&info, 0, sizeof(info));
> +			cifsInode = CIFS_I(newinode);
> +			dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
> +			info.Attributes = cpu_to_le32(dosattrs);
> +			tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
> +						   cifs_sb->local_nls,
> +						   cifs_sb->mnt_cifs_flags &
> +						   CIFS_MOUNT_MAP_SPECIAL_CHR);
> +			if (tmprc == 0)
> +				cifsInode->cifsAttrs = dosattrs;
> +		}
> +		if (dentry->d_inode) {
> +			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
> +				dentry->d_inode->i_mode = (mode | S_IFDIR);
> +
> +			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
> +				dentry->d_inode->i_uid = current_fsuid();
> +				if (inode->i_mode & S_ISGID)
> +					dentry->d_inode->i_gid = inode->i_gid;
> +				else
> +					dentry->d_inode->i_gid =
> +								current_fsgid();
> +			}
> +		}
> +	}
> +	return rc;
> +}
> +
> +static int
> +cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
> +		 const char *full_path, struct cifs_sb_info *cifs_sb,
> +		 struct cifs_tcon *tcon, const unsigned int xid)
> +{
> +	int rc = 0;
> +	u32 oplock = 0;
> +	FILE_UNIX_BASIC_INFO *info = NULL;
> +	struct inode *newinode = NULL;
> +	struct cifs_fattr fattr;
> +
> +	info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
> +	if (info == NULL) {
> +		rc = -ENOMEM;
> +		goto posix_mkdir_out;
> +	}
> +
> +	mode &= ~current_umask();
> +	rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
> +			     NULL /* netfid */, info, &oplock, full_path,
> +			     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
> +			     CIFS_MOUNT_MAP_SPECIAL_CHR);
> +	if (rc == -EOPNOTSUPP)
> +		goto posix_mkdir_out;
> +	else if (rc) {
> +		cFYI(1, "posix mkdir returned 0x%x", rc);
> +		d_drop(dentry);
> +		goto posix_mkdir_out;
> +	}
> +
> +	if (info->Type == cpu_to_le32(-1))
> +		/* no return info, go query for it */
> +		goto posix_mkdir_get_info;
> +	/*
> +	 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
> +	 * need to set uid/gid.
> +	 */
> +
> +	cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
> +	cifs_fill_uniqueid(inode->i_sb, &fattr);
> +	newinode = cifs_iget(inode->i_sb, &fattr);
> +	if (!newinode)
> +		goto posix_mkdir_get_info;
> +
> +	d_instantiate(dentry, newinode);
> +
> +#ifdef CONFIG_CIFS_DEBUG2
> +	cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
> +	     dentry->d_name.name, newinode);
> +
> +	if (newinode->i_nlink != 2)
> +		cFYI(1, "unexpected number of links %d", newinode->i_nlink);
> +#endif
> +
> +posix_mkdir_out:
> +	kfree(info);
> +	return rc;
> +posix_mkdir_get_info:
> +	rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
> +			      xid);
> +	goto posix_mkdir_out;
> +}
> +
>  int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  {
> -	int rc = 0, tmprc;
> +	int rc = 0;
>  	unsigned int xid;
>  	struct cifs_sb_info *cifs_sb;
>  	struct tcon_link *tlink;
>  	struct cifs_tcon *tcon;
> -	char *full_path = NULL;
> -	struct inode *newinode = NULL;
> -	struct cifs_fattr fattr;
> +	char *full_path;
>  
>  	cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
>  
> @@ -1248,145 +1397,23 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
>  
>  	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
>  				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
> -		u32 oplock = 0;
> -		FILE_UNIX_BASIC_INFO *pInfo =
> -			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
> -		if (pInfo == NULL) {
> -			rc = -ENOMEM;
> +		rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
> +				      tcon, xid);
> +		if (rc != -EOPNOTSUPP)
>  			goto mkdir_out;
> -		}
> -
> -		mode &= ~current_umask();
> -		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
> -				mode, NULL /* netfid */, pInfo, &oplock,
> -				full_path, cifs_sb->local_nls,
> -				cifs_sb->mnt_cifs_flags &
> -					CIFS_MOUNT_MAP_SPECIAL_CHR);
> -		if (rc == -EOPNOTSUPP) {
> -			kfree(pInfo);
> -			goto mkdir_retry_old;
> -		} else if (rc) {
> -			cFYI(1, "posix mkdir returned 0x%x", rc);
> -			d_drop(direntry);
> -		} else {
> -			if (pInfo->Type == cpu_to_le32(-1)) {
> -				/* no return info, go query for it */
> -				kfree(pInfo);
> -				goto mkdir_get_info;
> -			}
> -/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
> -	to set uid/gid */
> -
> -			cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
> -			cifs_fill_uniqueid(inode->i_sb, &fattr);
> -			newinode = cifs_iget(inode->i_sb, &fattr);
> -			if (!newinode) {
> -				kfree(pInfo);
> -				goto mkdir_get_info;
> -			}
> -
> -			d_instantiate(direntry, newinode);
> -
> -#ifdef CONFIG_CIFS_DEBUG2
> -			cFYI(1, "instantiated dentry %p %s to inode %p",
> -				direntry, direntry->d_name.name, newinode);
> -
> -			if (newinode->i_nlink != 2)
> -				cFYI(1, "unexpected number of links %d",
> -					newinode->i_nlink);
> -#endif
> -		}
> -		kfree(pInfo);
> -		goto mkdir_out;
>  	}
> -mkdir_retry_old:
> +
>  	/* BB add setting the equivalent of mode via CreateX w/ACLs */
>  	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
>  			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
>  	if (rc) {
>  		cFYI(1, "cifs_mkdir returned 0x%x", rc);
>  		d_drop(direntry);
> -	} else {
> -mkdir_get_info:
> -		if (tcon->unix_ext)
> -			rc = cifs_get_inode_info_unix(&newinode, full_path,
> -						      inode->i_sb, xid);
> -		else
> -			rc = cifs_get_inode_info(&newinode, full_path, NULL,
> -						 inode->i_sb, xid, NULL);
> -
> -		d_instantiate(direntry, newinode);
> -		 /* setting nlink not necessary except in cases where we
> -		  * failed to get it from the server or was set bogus */
> -		if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
> -			set_nlink(direntry->d_inode, 2);
> -
> -		mode &= ~current_umask();
> -		/* must turn on setgid bit if parent dir has it */
> -		if (inode->i_mode & S_ISGID)
> -			mode |= S_ISGID;
> -
> -		if (tcon->unix_ext) {
> -			struct cifs_unix_set_info_args args = {
> -				.mode	= mode,
> -				.ctime	= NO_CHANGE_64,
> -				.atime	= NO_CHANGE_64,
> -				.mtime	= NO_CHANGE_64,
> -				.device	= 0,
> -			};
> -			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
> -				args.uid = (__u64)current_fsuid();
> -				if (inode->i_mode & S_ISGID)
> -					args.gid = (__u64)inode->i_gid;
> -				else
> -					args.gid = (__u64)current_fsgid();
> -			} else {
> -				args.uid = NO_CHANGE_64;
> -				args.gid = NO_CHANGE_64;
> -			}
> -			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
> -					       cifs_sb->local_nls,
> -					       cifs_sb->mnt_cifs_flags &
> -						CIFS_MOUNT_MAP_SPECIAL_CHR);
> -		} else {
> -			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
> -			    (mode & S_IWUGO) == 0) {
> -				FILE_BASIC_INFO pInfo;
> -				struct cifsInodeInfo *cifsInode;
> -				u32 dosattrs;
> -
> -				memset(&pInfo, 0, sizeof(pInfo));
> -				cifsInode = CIFS_I(newinode);
> -				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
> -				pInfo.Attributes = cpu_to_le32(dosattrs);
> -				tmprc = CIFSSMBSetPathInfo(xid, tcon,
> -						full_path, &pInfo,
> -						cifs_sb->local_nls,
> -						cifs_sb->mnt_cifs_flags &
> -						CIFS_MOUNT_MAP_SPECIAL_CHR);
> -				if (tmprc == 0)
> -					cifsInode->cifsAttrs = dosattrs;
> -			}
> -			if (direntry->d_inode) {
> -				if (cifs_sb->mnt_cifs_flags &
> -				     CIFS_MOUNT_DYNPERM)
> -					direntry->d_inode->i_mode =
> -						(mode | S_IFDIR);
> -
> -				if (cifs_sb->mnt_cifs_flags &
> -				     CIFS_MOUNT_SET_UID) {
> -					direntry->d_inode->i_uid =
> -						current_fsuid();
> -					if (inode->i_mode & S_ISGID)
> -						direntry->d_inode->i_gid =
> -							inode->i_gid;
> -					else
> -						direntry->d_inode->i_gid =
> -							current_fsgid();
> -				}
> -			}
> -		}
> +		goto mkdir_out;
>  	}
> +
> +	rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
> +			      xid);
>  mkdir_out:
>  	/*
>  	 * Force revalidate to get parent dir info when needed since cached

Nice cleanup...

Reviewed-by: Jeff Layton <jlayton@redhat.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5aadeec..51fbdf2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -289,10 +289,10 @@  extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
 				  u16 fid, u32 pid_of_opener);
 
 extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
-				  struct cifs_tcon *tcon, char *file_name,
+				  struct cifs_tcon *tcon, const char *file_name,
 				  const struct cifs_unix_set_info_args *args,
 				  const struct nls_table *nls_codepage,
-				  int remap_special_chars);
+				  int remap);
 
 extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
 			const char *newName,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 846b803..ed472aa 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5945,7 +5945,7 @@  CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 
 int
 CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
-		       char *fileName,
+		       const char *file_name,
 		       const struct cifs_unix_set_info_args *args,
 		       const struct nls_table *nls_codepage, int remap)
 {
@@ -5966,14 +5966,14 @@  setPermsRetry:
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
+		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
 				       PATH_MAX, nls_codepage, remap);
 		name_len++;	/* trailing null */
 		name_len *= 2;
 	} else {	/* BB improve the check for buffer overruns BB */
-		name_len = strnlen(fileName, PATH_MAX);
+		name_len = strnlen(file_name, PATH_MAX);
 		name_len++;	/* trailing null */
-		strncpy(pSMB->FileName, fileName, name_len);
+		strncpy(pSMB->FileName, file_name, name_len);
 	}
 
 	params = 6 + name_len;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 35cb6a3..e9ba1a1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1219,16 +1219,165 @@  unlink_out:
 	return rc;
 }
 
+static int
+cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
+		 const char *full_path, struct cifs_sb_info *cifs_sb,
+		 struct cifs_tcon *tcon, const unsigned int xid)
+{
+	int rc = 0;
+	struct inode *newinode = NULL;
+
+	if (tcon->unix_ext)
+		rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+					      xid);
+	else
+		rc = cifs_get_inode_info(&newinode, full_path, NULL,
+					 inode->i_sb, xid, NULL);
+	if (rc)
+		return rc;
+
+	d_instantiate(dentry, newinode);
+	/*
+	 * setting nlink not necessary except in cases where we failed to get it
+	 * from the server or was set bogus
+	 */
+	if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
+		set_nlink(dentry->d_inode, 2);
+
+	mode &= ~current_umask();
+	/* must turn on setgid bit if parent dir has it */
+	if (inode->i_mode & S_ISGID)
+		mode |= S_ISGID;
+
+	if (tcon->unix_ext) {
+		struct cifs_unix_set_info_args args = {
+			.mode	= mode,
+			.ctime	= NO_CHANGE_64,
+			.atime	= NO_CHANGE_64,
+			.mtime	= NO_CHANGE_64,
+			.device	= 0,
+		};
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+			args.uid = (__u64)current_fsuid();
+			if (inode->i_mode & S_ISGID)
+				args.gid = (__u64)inode->i_gid;
+			else
+				args.gid = (__u64)current_fsgid();
+		} else {
+			args.uid = NO_CHANGE_64;
+			args.gid = NO_CHANGE_64;
+		}
+		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+				       cifs_sb->local_nls,
+				       cifs_sb->mnt_cifs_flags &
+				       CIFS_MOUNT_MAP_SPECIAL_CHR);
+	} else {
+		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+		    (mode & S_IWUGO) == 0) {
+			FILE_BASIC_INFO info;
+			struct cifsInodeInfo *cifsInode;
+			u32 dosattrs;
+			int tmprc;
+
+			memset(&info, 0, sizeof(info));
+			cifsInode = CIFS_I(newinode);
+			dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+			info.Attributes = cpu_to_le32(dosattrs);
+			tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
+						   cifs_sb->local_nls,
+						   cifs_sb->mnt_cifs_flags &
+						   CIFS_MOUNT_MAP_SPECIAL_CHR);
+			if (tmprc == 0)
+				cifsInode->cifsAttrs = dosattrs;
+		}
+		if (dentry->d_inode) {
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+				dentry->d_inode->i_mode = (mode | S_IFDIR);
+
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+				dentry->d_inode->i_uid = current_fsuid();
+				if (inode->i_mode & S_ISGID)
+					dentry->d_inode->i_gid = inode->i_gid;
+				else
+					dentry->d_inode->i_gid =
+								current_fsgid();
+			}
+		}
+	}
+	return rc;
+}
+
+static int
+cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
+		 const char *full_path, struct cifs_sb_info *cifs_sb,
+		 struct cifs_tcon *tcon, const unsigned int xid)
+{
+	int rc = 0;
+	u32 oplock = 0;
+	FILE_UNIX_BASIC_INFO *info = NULL;
+	struct inode *newinode = NULL;
+	struct cifs_fattr fattr;
+
+	info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+	if (info == NULL) {
+		rc = -ENOMEM;
+		goto posix_mkdir_out;
+	}
+
+	mode &= ~current_umask();
+	rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
+			     NULL /* netfid */, info, &oplock, full_path,
+			     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+			     CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc == -EOPNOTSUPP)
+		goto posix_mkdir_out;
+	else if (rc) {
+		cFYI(1, "posix mkdir returned 0x%x", rc);
+		d_drop(dentry);
+		goto posix_mkdir_out;
+	}
+
+	if (info->Type == cpu_to_le32(-1))
+		/* no return info, go query for it */
+		goto posix_mkdir_get_info;
+	/*
+	 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
+	 * need to set uid/gid.
+	 */
+
+	cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
+	cifs_fill_uniqueid(inode->i_sb, &fattr);
+	newinode = cifs_iget(inode->i_sb, &fattr);
+	if (!newinode)
+		goto posix_mkdir_get_info;
+
+	d_instantiate(dentry, newinode);
+
+#ifdef CONFIG_CIFS_DEBUG2
+	cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
+	     dentry->d_name.name, newinode);
+
+	if (newinode->i_nlink != 2)
+		cFYI(1, "unexpected number of links %d", newinode->i_nlink);
+#endif
+
+posix_mkdir_out:
+	kfree(info);
+	return rc;
+posix_mkdir_get_info:
+	rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
+			      xid);
+	goto posix_mkdir_out;
+}
+
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 {
-	int rc = 0, tmprc;
+	int rc = 0;
 	unsigned int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
-	char *full_path = NULL;
-	struct inode *newinode = NULL;
-	struct cifs_fattr fattr;
+	char *full_path;
 
 	cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
 
@@ -1248,145 +1397,23 @@  int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
 
 	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
 				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-		u32 oplock = 0;
-		FILE_UNIX_BASIC_INFO *pInfo =
-			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
-		if (pInfo == NULL) {
-			rc = -ENOMEM;
+		rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
+				      tcon, xid);
+		if (rc != -EOPNOTSUPP)
 			goto mkdir_out;
-		}
-
-		mode &= ~current_umask();
-		rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
-				mode, NULL /* netfid */, pInfo, &oplock,
-				full_path, cifs_sb->local_nls,
-				cifs_sb->mnt_cifs_flags &
-					CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if (rc == -EOPNOTSUPP) {
-			kfree(pInfo);
-			goto mkdir_retry_old;
-		} else if (rc) {
-			cFYI(1, "posix mkdir returned 0x%x", rc);
-			d_drop(direntry);
-		} else {
-			if (pInfo->Type == cpu_to_le32(-1)) {
-				/* no return info, go query for it */
-				kfree(pInfo);
-				goto mkdir_get_info;
-			}
-/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
-	to set uid/gid */
-
-			cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
-			cifs_fill_uniqueid(inode->i_sb, &fattr);
-			newinode = cifs_iget(inode->i_sb, &fattr);
-			if (!newinode) {
-				kfree(pInfo);
-				goto mkdir_get_info;
-			}
-
-			d_instantiate(direntry, newinode);
-
-#ifdef CONFIG_CIFS_DEBUG2
-			cFYI(1, "instantiated dentry %p %s to inode %p",
-				direntry, direntry->d_name.name, newinode);
-
-			if (newinode->i_nlink != 2)
-				cFYI(1, "unexpected number of links %d",
-					newinode->i_nlink);
-#endif
-		}
-		kfree(pInfo);
-		goto mkdir_out;
 	}
-mkdir_retry_old:
+
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
 	rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		cFYI(1, "cifs_mkdir returned 0x%x", rc);
 		d_drop(direntry);
-	} else {
-mkdir_get_info:
-		if (tcon->unix_ext)
-			rc = cifs_get_inode_info_unix(&newinode, full_path,
-						      inode->i_sb, xid);
-		else
-			rc = cifs_get_inode_info(&newinode, full_path, NULL,
-						 inode->i_sb, xid, NULL);
-
-		d_instantiate(direntry, newinode);
-		 /* setting nlink not necessary except in cases where we
-		  * failed to get it from the server or was set bogus */
-		if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
-			set_nlink(direntry->d_inode, 2);
-
-		mode &= ~current_umask();
-		/* must turn on setgid bit if parent dir has it */
-		if (inode->i_mode & S_ISGID)
-			mode |= S_ISGID;
-
-		if (tcon->unix_ext) {
-			struct cifs_unix_set_info_args args = {
-				.mode	= mode,
-				.ctime	= NO_CHANGE_64,
-				.atime	= NO_CHANGE_64,
-				.mtime	= NO_CHANGE_64,
-				.device	= 0,
-			};
-			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-				args.uid = (__u64)current_fsuid();
-				if (inode->i_mode & S_ISGID)
-					args.gid = (__u64)inode->i_gid;
-				else
-					args.gid = (__u64)current_fsgid();
-			} else {
-				args.uid = NO_CHANGE_64;
-				args.gid = NO_CHANGE_64;
-			}
-			CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
-					       cifs_sb->local_nls,
-					       cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
-		} else {
-			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
-			    (mode & S_IWUGO) == 0) {
-				FILE_BASIC_INFO pInfo;
-				struct cifsInodeInfo *cifsInode;
-				u32 dosattrs;
-
-				memset(&pInfo, 0, sizeof(pInfo));
-				cifsInode = CIFS_I(newinode);
-				dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
-				pInfo.Attributes = cpu_to_le32(dosattrs);
-				tmprc = CIFSSMBSetPathInfo(xid, tcon,
-						full_path, &pInfo,
-						cifs_sb->local_nls,
-						cifs_sb->mnt_cifs_flags &
-						CIFS_MOUNT_MAP_SPECIAL_CHR);
-				if (tmprc == 0)
-					cifsInode->cifsAttrs = dosattrs;
-			}
-			if (direntry->d_inode) {
-				if (cifs_sb->mnt_cifs_flags &
-				     CIFS_MOUNT_DYNPERM)
-					direntry->d_inode->i_mode =
-						(mode | S_IFDIR);
-
-				if (cifs_sb->mnt_cifs_flags &
-				     CIFS_MOUNT_SET_UID) {
-					direntry->d_inode->i_uid =
-						current_fsuid();
-					if (inode->i_mode & S_ISGID)
-						direntry->d_inode->i_gid =
-							inode->i_gid;
-					else
-						direntry->d_inode->i_gid =
-							current_fsgid();
-				}
-			}
-		}
+		goto mkdir_out;
 	}
+
+	rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
+			      xid);
 mkdir_out:
 	/*
 	 * Force revalidate to get parent dir info when needed since cached