Commit 2dd29d3133ad4c7926ea03b8431e604373c4ad65
1 parent
5268df2ead
Exists in
master
and in
7 other branches
[CIFS] New CIFS POSIX mkdir performance improvement
Signed-off-by: Steve French <sfrench@us.ibm.com>
Showing 5 changed files with 340 additions and 15 deletions Side-by-side Diff
fs/cifs/CHANGES
... | ... | @@ -12,7 +12,10 @@ |
12 | 12 | on server which does not support the Unix Extensions). Remove read only dos |
13 | 13 | attribute on chmod when adding any write permission (ie on any of |
14 | 14 | user/group/other (not all of user/group/other ie 0222) when |
15 | -mounted to windows. | |
15 | +mounted to windows. Add support for POSIX MkDir (slight performance | |
16 | +enhancement and eliminates the network race between the mkdir and set | |
17 | +path info of the mode). | |
18 | + | |
16 | 19 | |
17 | 20 | Version 1.47 |
18 | 21 | ------------ |
fs/cifs/cifspdu.h
... | ... | @@ -1388,7 +1388,7 @@ |
1388 | 1388 | #define SMB_SET_POSIX_LOCK 0x208 |
1389 | 1389 | #define SMB_POSIX_OPEN 0x209 |
1390 | 1390 | #define SMB_POSIX_UNLINK 0x20a |
1391 | -#define SMB_SET_FILE_UNIX_INFO2 | |
1391 | +#define SMB_SET_FILE_UNIX_INFO2 0x20b | |
1392 | 1392 | #define SMB_SET_FILE_BASIC_INFO2 0x3ec |
1393 | 1393 | #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */ |
1394 | 1394 | #define SMB_FILE_ALL_INFO2 0x3fa |
1395 | 1395 | |
1396 | 1396 | |
1397 | 1397 | |
... | ... | @@ -2109,22 +2109,40 @@ |
2109 | 2109 | |
2110 | 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 | + | |
2112 | 2125 | typedef struct { |
2113 | - __u32 OpenFlags; /* same as NT CreateX */ | |
2114 | - __u32 PosixOpenFlags; | |
2115 | - __u32 Mode; | |
2116 | - __u16 Level; /* reply level requested (see QPathInfo levels) */ | |
2117 | - __u16 Pad; /* reserved - MBZ */ | |
2126 | + __le32 OpenFlags; /* same as NT CreateX */ | |
2127 | + __le32 PosixOpenFlags; | |
2128 | + __le64 Permissions; | |
2129 | + __le16 Level; /* reply level requested (see QPathInfo levels) */ | |
2118 | 2130 | } __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ |
2119 | 2131 | |
2120 | 2132 | typedef 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 | 2139 | } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ |
2123 | 2140 | |
2124 | 2141 | |
2125 | 2142 | struct file_internal_info { |
2126 | 2143 | __u64 UniqueId; /* inode number */ |
2127 | 2144 | } __attribute__((packed)); /* level 0x3ee */ |
2145 | + | |
2128 | 2146 | struct file_mode_info { |
2129 | 2147 | __le32 Mode; |
2130 | 2148 | } __attribute__((packed)); /* level 0x3f8 */ |
fs/cifs/cifsproto.h
1 | 1 | /* |
2 | 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 | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | 6 | * |
7 | 7 | * This library is free software; you can redistribute it and/or modify |
... | ... | @@ -244,6 +244,11 @@ |
244 | 244 | const int access_flags, const int omode, |
245 | 245 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, |
246 | 246 | const struct nls_table *nls_codepage, int remap); |
247 | +extern 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); | |
247 | 252 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, |
248 | 253 | const int smb_file_id); |
249 | 254 |
fs/cifs/cifssmb.c
1 | 1 | /* |
2 | 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 | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | 6 | * |
7 | 7 | * Contains the routines for constructing the SMB PDUs themselves |
... | ... | @@ -24,8 +24,8 @@ |
24 | 24 | /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ |
25 | 25 | /* These are mostly routines that operate on a pathname, or on a tree id */ |
26 | 26 | /* (mounted volume), but there are eight handle based routines which must be */ |
27 | - /* treated slightly different for reconnection purposes since we never want */ | |
28 | - /* to reuse a stale file handle and the caller knows the file handle */ | |
27 | + /* treated slightly differently for reconnection purposes since we never */ | |
28 | + /* want to reuse a stale file handle and only the caller knows the file info */ | |
29 | 29 | |
30 | 30 | #include <linux/fs.h> |
31 | 31 | #include <linux/kernel.h> |
... | ... | @@ -911,6 +911,127 @@ |
911 | 911 | if (rc == -EAGAIN) |
912 | 912 | goto MkDirRetry; |
913 | 913 | return rc; |
914 | +} | |
915 | + | |
916 | +int | |
917 | +CIFSPOSIXCreate(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")); | |
933 | +PsxCreat: | |
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 | + | |
1026 | +psx_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; | |
914 | 1035 | } |
915 | 1036 | |
916 | 1037 | static __u16 convert_disposition(int disposition) |
fs/cifs/inode.c
1 | 1 | /* |
2 | 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 | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | 6 | * |
7 | 7 | * This library is free software; you can redistribute it and/or modify |
... | ... | @@ -734,6 +734,133 @@ |
734 | 734 | return rc; |
735 | 735 | } |
736 | 736 | |
737 | +static 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 | + | |
737 | 864 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) |
738 | 865 | { |
739 | 866 | int rc = 0; |
... | ... | @@ -755,6 +882,53 @@ |
755 | 882 | FreeXid(xid); |
756 | 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 | 932 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ |
759 | 933 | rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, |
760 | 934 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
... | ... | @@ -762,6 +936,7 @@ |
762 | 936 | cFYI(1, ("cifs_mkdir returned 0x%x", rc)); |
763 | 937 | d_drop(direntry); |
764 | 938 | } else { |
939 | +mkdir_get_info: | |
765 | 940 | inc_nlink(inode); |
766 | 941 | if (pTcon->ses->capabilities & CAP_UNIX) |
767 | 942 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
... | ... | @@ -775,8 +950,10 @@ |
775 | 950 | else |
776 | 951 | direntry->d_op = &cifs_dentry_ops; |
777 | 952 | d_instantiate(direntry, newinode); |
778 | - if (direntry->d_inode) | |
779 | - direntry->d_inode->i_nlink = 2; | |
953 | + /* setting nlink not necessary except in cases where we | |
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 | 957 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
781 | 958 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
782 | 959 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
... | ... | @@ -812,6 +989,7 @@ |
812 | 989 | } |
813 | 990 | } |
814 | 991 | } |
992 | +mkdir_out: | |
815 | 993 | kfree(full_path); |
816 | 994 | FreeXid(xid); |
817 | 995 | return rc; |