aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/CHANGES5
-rw-r--r--fs/cifs/cifspdu.h32
-rw-r--r--fs/cifs/cifsproto.h7
-rw-r--r--fs/cifs/cifssmb.c127
-rw-r--r--fs/cifs/inode.c184
5 files changed, 340 insertions, 15 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index f75bdc661769..713fec669135 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -12,7 +12,10 @@ when archive dos attribute not set and we are changing mode back to writeable
12on server which does not support the Unix Extensions). Remove read only dos 12on server which does not support the Unix Extensions). Remove read only dos
13attribute on chmod when adding any write permission (ie on any of 13attribute on chmod when adding any write permission (ie on any of
14user/group/other (not all of user/group/other ie 0222) when 14user/group/other (not all of user/group/other ie 0222) when
15mounted to windows. 15mounted to windows. Add support for POSIX MkDir (slight performance
16enhancement and eliminates the network race between the mkdir and set
17path info of the mode).
18
16 19
17Version 1.47 20Version 1.47
18------------ 21------------
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 4d8948e8762c..d619ca7d1416 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1388,7 +1388,7 @@ struct smb_t2_rsp {
1388#define SMB_SET_POSIX_LOCK 0x208 1388#define SMB_SET_POSIX_LOCK 0x208
1389#define SMB_POSIX_OPEN 0x209 1389#define SMB_POSIX_OPEN 0x209
1390#define SMB_POSIX_UNLINK 0x20a 1390#define SMB_POSIX_UNLINK 0x20a
1391#define SMB_SET_FILE_UNIX_INFO2 1391#define SMB_SET_FILE_UNIX_INFO2 0x20b
1392#define SMB_SET_FILE_BASIC_INFO2 0x3ec 1392#define SMB_SET_FILE_BASIC_INFO2 0x3ec
1393#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */ 1393#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
1394#define SMB_FILE_ALL_INFO2 0x3fa 1394#define SMB_FILE_ALL_INFO2 0x3fa
@@ -2109,22 +2109,40 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
2109 2109
2110/* end of POSIX ACL definitions */ 2110/* end of POSIX ACL definitions */
2111 2111
2112/* POSIX Open Flags */
2113#define SMB_O_RDONLY 0x1
2114#define SMB_O_WRONLY 0x2
2115#define SMB_O_RDWR 0x4
2116#define SMB_O_CREAT 0x10
2117#define SMB_O_EXCL 0x20
2118#define SMB_O_TRUNC 0x40
2119#define SMB_O_APPEND 0x80
2120#define SMB_O_SYNC 0x100
2121#define SMB_O_DIRECTORY 0x200
2122#define SMB_O_NOFOLLOW 0x400
2123#define SMB_O_DIRECT 0x800
2124
2112typedef struct { 2125typedef struct {
2113 __u32 OpenFlags; /* same as NT CreateX */ 2126 __le32 OpenFlags; /* same as NT CreateX */
2114 __u32 PosixOpenFlags; 2127 __le32 PosixOpenFlags;
2115 __u32 Mode; 2128 __le64 Permissions;
2116 __u16 Level; /* reply level requested (see QPathInfo levels) */ 2129 __le16 Level; /* reply level requested (see QPathInfo levels) */
2117 __u16 Pad; /* reserved - MBZ */
2118} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ 2130} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
2119 2131
2120typedef struct { 2132typedef struct {
2121 /* reply varies based on requested level */ 2133 __le16 OplockFlags;
2134 __u16 Fid;
2135 __le32 CreateAction;
2136 __le16 ReturnedLevel;
2137 __le16 Pad;
2138 /* struct following varies based on requested level */
2122} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ 2139} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
2123 2140
2124 2141
2125struct file_internal_info { 2142struct file_internal_info {
2126 __u64 UniqueId; /* inode number */ 2143 __u64 UniqueId; /* inode number */
2127} __attribute__((packed)); /* level 0x3ee */ 2144} __attribute__((packed)); /* level 0x3ee */
2145
2128struct file_mode_info { 2146struct file_mode_info {
2129 __le32 Mode; 2147 __le32 Mode;
2130} __attribute__((packed)); /* level 0x3f8 */ 2148} __attribute__((packed)); /* level 0x3f8 */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 32eb1acab630..5d163e2b6143 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsproto.h 2 * fs/cifs/cifsproto.h
3 * 3 *
4 * Copyright (c) International Business Machines Corp., 2002,2006 4 * Copyright (c) International Business Machines Corp., 2002,2007
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * This library is free software; you can redistribute it and/or modify
@@ -244,6 +244,11 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
244 const int access_flags, const int omode, 244 const int access_flags, const int omode,
245 __u16 * netfid, int *pOplock, FILE_ALL_INFO *, 245 __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
246 const struct nls_table *nls_codepage, int remap); 246 const struct nls_table *nls_codepage, int remap);
247extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
248 u32 posix_flags, __u64 mode, __u16 * netfid,
249 FILE_UNIX_BASIC_INFO *pRetData,
250 __u32 *pOplock, const char *name,
251 const struct nls_table *nls_codepage, int remap);
247extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, 252extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
248 const int smb_file_id); 253 const int smb_file_id);
249 254
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 48fc0c2ab0e5..a7d3d8e5c6c5 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifssmb.c 2 * fs/cifs/cifssmb.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2002,2006 4 * Copyright (C) International Business Machines Corp., 2002,2007
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * Contains the routines for constructing the SMB PDUs themselves 7 * Contains the routines for constructing the SMB PDUs themselves
@@ -24,8 +24,8 @@
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ 24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */ 25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */ 26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */ 27 /* treated slightly differently for reconnection purposes since we never */
28 /* to reuse a stale file handle and the caller knows the file handle */ 28 /* want to reuse a stale file handle and only the caller knows the file info */
29 29
30#include <linux/fs.h> 30#include <linux/fs.h>
31#include <linux/kernel.h> 31#include <linux/kernel.h>
@@ -913,6 +913,127 @@ MkDirRetry:
913 return rc; 913 return rc;
914} 914}
915 915
916int
917CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
918 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
919 __u32 *pOplock, const char *name,
920 const struct nls_table *nls_codepage, int remap)
921{
922 TRANSACTION2_SPI_REQ *pSMB = NULL;
923 TRANSACTION2_SPI_RSP *pSMBr = NULL;
924 int name_len;
925 int rc = 0;
926 int bytes_returned = 0;
927 char *data_offset;
928 __u16 params, param_offset, offset, byte_count, count;
929 OPEN_PSX_REQ * pdata;
930 OPEN_PSX_RSP * psx_rsp;
931
932 cFYI(1, ("In POSIX Create"));
933PsxCreat:
934 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len =
941 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
942 PATH_MAX, nls_codepage, remap);
943 name_len++; /* trailing null */
944 name_len *= 2;
945 } else { /* BB improve the check for buffer overruns BB */
946 name_len = strnlen(name, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->FileName, name, name_len);
949 }
950
951 params = 6 + name_len;
952 count = sizeof(OPEN_PSX_REQ);
953 pSMB->MaxParameterCount = cpu_to_le16(2);
954 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
955 pSMB->MaxSetupCount = 0;
956 pSMB->Reserved = 0;
957 pSMB->Flags = 0;
958 pSMB->Timeout = 0;
959 pSMB->Reserved2 = 0;
960 param_offset = offsetof(struct smb_com_transaction2_spi_req,
961 InformationLevel) - 4;
962 offset = param_offset + params;
963 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
964 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
965 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
966 pdata->Permissions = cpu_to_le64(mode);
967 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
968 pdata->OpenFlags = cpu_to_le32(*pOplock);
969 pSMB->ParameterOffset = cpu_to_le16(param_offset);
970 pSMB->DataOffset = cpu_to_le16(offset);
971 pSMB->SetupCount = 1;
972 pSMB->Reserved3 = 0;
973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
974 byte_count = 3 /* pad */ + params + count;
975
976 pSMB->DataCount = cpu_to_le16(count);
977 pSMB->ParameterCount = cpu_to_le16(params);
978 pSMB->TotalDataCount = pSMB->DataCount;
979 pSMB->TotalParameterCount = pSMB->ParameterCount;
980 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
981 pSMB->Reserved4 = 0;
982 pSMB->hdr.smb_buf_length += byte_count;
983 pSMB->ByteCount = cpu_to_le16(byte_count);
984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
986 if (rc) {
987 cFYI(1, ("Posix create returned %d", rc));
988 goto psx_create_err;
989 }
990
991 cFYI(1,("copying inode info"));
992 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
993
994 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
995 rc = -EIO; /* bad smb */
996 goto psx_create_err;
997 }
998
999 /* copy return information to pRetData */
1000 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1001 + le16_to_cpu(pSMBr->t2.DataOffset));
1002
1003 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1004 if(netfid)
1005 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1006 /* Let caller know file was created so we can set the mode. */
1007 /* Do we care about the CreateAction in any other cases? */
1008 if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1009 *pOplock |= CIFS_CREATE_ACTION;
1010 /* check to make sure response data is there */
1011 if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC)
1012 pRetData->Type = -1; /* unknown */
1013 else {
1014 if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1015 + sizeof(FILE_UNIX_BASIC_INFO)) {
1016 cERROR(1,("Open response data too small"));
1017 pRetData->Type = -1;
1018 goto psx_create_err;
1019 }
1020 memcpy((char *) pRetData,
1021 (char *)&psx_rsp + sizeof(OPEN_PSX_RSP),
1022 sizeof (FILE_UNIX_BASIC_INFO));
1023 }
1024
1025
1026psx_create_err:
1027 cifs_buf_release(pSMB);
1028
1029 cifs_stats_inc(&tcon->num_mkdirs);
1030
1031 if (rc == -EAGAIN)
1032 goto PsxCreat;
1033
1034 return rc;
1035}
1036
916static __u16 convert_disposition(int disposition) 1037static __u16 convert_disposition(int disposition)
917{ 1038{
918 __u16 ofun = 0; 1039 __u16 ofun = 0;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index eeea33752e68..9b7e0dbdd826 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/inode.c 2 * fs/cifs/inode.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2002,2005 4 * Copyright (C) International Business Machines Corp., 2002,2007
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * This library is free software; you can redistribute it and/or modify
@@ -734,6 +734,133 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
734 return rc; 734 return rc;
735} 735}
736 736
737static void posix_fill_in_inode(struct inode *tmp_inode,
738 FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
739{
740 loff_t local_size;
741 struct timespec local_mtime;
742
743 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
744 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
745
746 __u32 type = le32_to_cpu(pData->Type);
747 __u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
748 __u64 end_of_file = le64_to_cpu(pData->EndOfFile);
749 cifsInfo->time = jiffies;
750 atomic_inc(&cifsInfo->inUse);
751
752 /* save mtime and size */
753 local_mtime = tmp_inode->i_mtime;
754 local_size = tmp_inode->i_size;
755
756 tmp_inode->i_atime =
757 cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
758 tmp_inode->i_mtime =
759 cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
760 tmp_inode->i_ctime =
761 cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
762
763 tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
764 /* since we set the inode type below we need to mask off type
765 to avoid strange results if bits above were corrupt */
766 tmp_inode->i_mode &= ~S_IFMT;
767 if (type == UNIX_FILE) {
768 *pobject_type = DT_REG;
769 tmp_inode->i_mode |= S_IFREG;
770 } else if (type == UNIX_SYMLINK) {
771 *pobject_type = DT_LNK;
772 tmp_inode->i_mode |= S_IFLNK;
773 } else if (type == UNIX_DIR) {
774 *pobject_type = DT_DIR;
775 tmp_inode->i_mode |= S_IFDIR;
776 } else if (type == UNIX_CHARDEV) {
777 *pobject_type = DT_CHR;
778 tmp_inode->i_mode |= S_IFCHR;
779 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
780 le64_to_cpu(pData->DevMinor) & MINORMASK);
781 } else if (type == UNIX_BLOCKDEV) {
782 *pobject_type = DT_BLK;
783 tmp_inode->i_mode |= S_IFBLK;
784 tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
785 le64_to_cpu(pData->DevMinor) & MINORMASK);
786 } else if (type == UNIX_FIFO) {
787 *pobject_type = DT_FIFO;
788 tmp_inode->i_mode |= S_IFIFO;
789 } else if (type == UNIX_SOCKET) {
790 *pobject_type = DT_SOCK;
791 tmp_inode->i_mode |= S_IFSOCK;
792 } else {
793 /* safest to just call it a file */
794 *pobject_type = DT_REG;
795 tmp_inode->i_mode |= S_IFREG;
796 cFYI(1,("unknown inode type %d",type));
797 }
798
799 tmp_inode->i_uid = le64_to_cpu(pData->Uid);
800 tmp_inode->i_gid = le64_to_cpu(pData->Gid);
801 tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
802
803 spin_lock(&tmp_inode->i_lock);
804 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
805 /* can not safely change the file size here if the
806 client is writing to it due to potential races */
807 i_size_write(tmp_inode, end_of_file);
808
809 /* 512 bytes (2**9) is the fake blocksize that must be used */
810 /* for this calculation, not the real blocksize */
811 tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
812 }
813 spin_unlock(&tmp_inode->i_lock);
814
815 if (S_ISREG(tmp_inode->i_mode)) {
816 cFYI(1, ("File inode"));
817 tmp_inode->i_op = &cifs_file_inode_ops;
818
819 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
820 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
821 tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
822 else
823 tmp_inode->i_fop = &cifs_file_direct_ops;
824
825 } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
826 tmp_inode->i_fop = &cifs_file_nobrl_ops;
827 else
828 tmp_inode->i_fop = &cifs_file_ops;
829
830 if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
831 (cifs_sb->tcon->ses->server->maxBuf <
832 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
833 tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
834 else
835 tmp_inode->i_data.a_ops = &cifs_addr_ops;
836
837 if(isNewInode)
838 return; /* No sense invalidating pages for new inode since we
839 have not started caching readahead file data yet */
840
841 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
842 (local_size == tmp_inode->i_size)) {
843 cFYI(1, ("inode exists but unchanged"));
844 } else {
845 /* file may have changed on server */
846 cFYI(1, ("invalidate inode, readdir detected change"));
847 invalidate_remote_inode(tmp_inode);
848 }
849 } else if (S_ISDIR(tmp_inode->i_mode)) {
850 cFYI(1, ("Directory inode"));
851 tmp_inode->i_op = &cifs_dir_inode_ops;
852 tmp_inode->i_fop = &cifs_dir_ops;
853 } else if (S_ISLNK(tmp_inode->i_mode)) {
854 cFYI(1, ("Symbolic Link inode"));
855 tmp_inode->i_op = &cifs_symlink_inode_ops;
856/* tmp_inode->i_fop = *//* do not need to set to anything */
857 } else {
858 cFYI(1, ("Special inode"));
859 init_special_inode(tmp_inode, tmp_inode->i_mode,
860 tmp_inode->i_rdev);
861 }
862}
863
737int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) 864int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
738{ 865{
739 int rc = 0; 866 int rc = 0;
@@ -755,6 +882,53 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
755 FreeXid(xid); 882 FreeXid(xid);
756 return -ENOMEM; 883 return -ENOMEM;
757 } 884 }
885
886 if((pTcon->ses->capabilities & CAP_UNIX) &&
887 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
888 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
889 u32 oplock = 0;
890 FILE_UNIX_BASIC_INFO * pInfo =
891 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
892 if(pInfo == NULL) {
893 rc = -ENOMEM;
894 goto mkdir_out;
895 }
896
897 rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
898 mode, NULL /* netfid */, pInfo, &oplock,
899 full_path, cifs_sb->local_nls,
900 cifs_sb->mnt_cifs_flags &
901 CIFS_MOUNT_MAP_SPECIAL_CHR);
902 if (rc) {
903 cFYI(1, ("posix mkdir returned 0x%x", rc));
904 d_drop(direntry);
905 } else {
906 if (pInfo->Type == -1) /* no return info - go query */
907 goto mkdir_get_info;
908/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
909 inc_nlink(inode);
910 if (pTcon->nocase)
911 direntry->d_op = &cifs_ci_dentry_ops;
912 else
913 direntry->d_op = &cifs_dentry_ops;
914 d_instantiate(direntry, newinode);
915 if (direntry->d_inode) {
916 int obj_type;
917 direntry->d_inode->i_nlink = 2;
918 /* already checked in POSIXCreate whether
919 frame was long enough */
920 posix_fill_in_inode(direntry->d_inode,
921 pInfo, &obj_type, 1 /* NewInode */);
922 /* could double check that we actually
923 * created what we thought we did ie
924 * a directory
925 */
926 }
927 }
928 kfree(pInfo);
929 goto mkdir_out;
930 }
931
758 /* BB add setting the equivalent of mode via CreateX w/ACLs */ 932 /* BB add setting the equivalent of mode via CreateX w/ACLs */
759 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, 933 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
760 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 934 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -762,6 +936,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
762 cFYI(1, ("cifs_mkdir returned 0x%x", rc)); 936 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
763 d_drop(direntry); 937 d_drop(direntry);
764 } else { 938 } else {
939mkdir_get_info:
765 inc_nlink(inode); 940 inc_nlink(inode);
766 if (pTcon->ses->capabilities & CAP_UNIX) 941 if (pTcon->ses->capabilities & CAP_UNIX)
767 rc = cifs_get_inode_info_unix(&newinode, full_path, 942 rc = cifs_get_inode_info_unix(&newinode, full_path,
@@ -775,8 +950,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
775 else 950 else
776 direntry->d_op = &cifs_dentry_ops; 951 direntry->d_op = &cifs_dentry_ops;
777 d_instantiate(direntry, newinode); 952 d_instantiate(direntry, newinode);
778 if (direntry->d_inode) 953 /* setting nlink not necessary except in cases where we
779 direntry->d_inode->i_nlink = 2; 954 * failed to get it from the server or was set bogus */
955 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
956 direntry->d_inode->i_nlink = 2;
780 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) 957 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
781 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 958 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
782 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 959 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -812,6 +989,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
812 } 989 }
813 } 990 }
814 } 991 }
992mkdir_out:
815 kfree(full_path); 993 kfree(full_path);
816 FreeXid(xid); 994 FreeXid(xid);
817 return rc; 995 return rc;