diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 5 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 32 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 7 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 127 | ||||
-rw-r--r-- | fs/cifs/inode.c | 184 |
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 | |||
12 | on server which does not support the Unix Extensions). Remove read only dos | 12 | on server which does not support the Unix Extensions). Remove read only dos |
13 | attribute on chmod when adding any write permission (ie on any of | 13 | attribute on chmod when adding any write permission (ie on any of |
14 | user/group/other (not all of user/group/other ie 0222) when | 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 | Version 1.47 | 20 | Version 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 | |||
2112 | typedef struct { | 2125 | typedef 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 | ||
2120 | typedef struct { | 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 | } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ | 2139 | } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ |
2123 | 2140 | ||
2124 | 2141 | ||
2125 | struct file_internal_info { | 2142 | struct file_internal_info { |
2126 | __u64 UniqueId; /* inode number */ | 2143 | __u64 UniqueId; /* inode number */ |
2127 | } __attribute__((packed)); /* level 0x3ee */ | 2144 | } __attribute__((packed)); /* level 0x3ee */ |
2145 | |||
2128 | struct file_mode_info { | 2146 | struct 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); |
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 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | 252 | extern 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 | ||
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; | ||
1035 | } | ||
1036 | |||
916 | static __u16 convert_disposition(int disposition) | 1037 | static __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 | ||
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 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | 864 | int 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 { |
939 | mkdir_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 | } |
992 | mkdir_out: | ||
815 | kfree(full_path); | 993 | kfree(full_path); |
816 | FreeXid(xid); | 994 | FreeXid(xid); |
817 | return rc; | 995 | return rc; |