diff options
-rw-r--r-- | fs/cifs/CHANGES | 4 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 85 | ||||
-rw-r--r-- | fs/cifs/inode.c | 14 |
5 files changed, 103 insertions, 11 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index f92e0ee661ae..6d84ca2beead 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,7 +1,9 @@ | |||
1 | Version 1.50 | 1 | Version 1.50 |
2 | ------------ | 2 | ------------ |
3 | Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is | 3 | Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is |
4 | done with "serverino" mount option). | 4 | done with "serverino" mount option). Add support for POSIX Unlink |
5 | (helps with certain sharing violation cases when server such as | ||
6 | Samba supports newer POSIX CIFS Protocol Extensions). | ||
5 | 7 | ||
6 | Version 1.49 | 8 | Version 1.49 |
7 | ------------ | 9 | ------------ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 9044d9886f0d..6a2056e58ceb 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -2155,6 +2155,12 @@ typedef struct { | |||
2155 | /* struct following varies based on requested level */ | 2155 | /* struct following varies based on requested level */ |
2156 | } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ | 2156 | } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ |
2157 | 2157 | ||
2158 | #define SMB_POSIX_UNLINK_FILE_TARGET 0 | ||
2159 | #define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1 | ||
2160 | |||
2161 | struct unlink_psx_rq { /* level 0x20a SetPathInfo */ | ||
2162 | __le16 type; | ||
2163 | } __attribute__((packed)); | ||
2158 | 2164 | ||
2159 | struct file_internal_info { | 2165 | struct file_internal_info { |
2160 | __u64 UniqueId; /* inode number */ | 2166 | __u64 UniqueId; /* inode number */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 3a76c72f3c89..04a69dafedba 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -196,7 +196,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, | |||
196 | extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, | 196 | extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, |
197 | const char *name, const struct nls_table *nls_codepage, | 197 | const char *name, const struct nls_table *nls_codepage, |
198 | int remap_special_chars); | 198 | int remap_special_chars); |
199 | 199 | extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, | |
200 | const char *name, __u16 type, | ||
201 | const struct nls_table *nls_codepage, | ||
202 | int remap_special_chars); | ||
200 | extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, | 203 | extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, |
201 | const char *name, | 204 | const char *name, |
202 | const struct nls_table *nls_codepage, | 205 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 3ab78b776977..b339f5f128da 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -789,6 +789,82 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
789 | } | 789 | } |
790 | 790 | ||
791 | int | 791 | int |
792 | CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, | ||
793 | __u16 type, const struct nls_table *nls_codepage, int remap) | ||
794 | { | ||
795 | TRANSACTION2_SPI_REQ *pSMB = NULL; | ||
796 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | ||
797 | struct unlink_psx_rq *pRqD; | ||
798 | int name_len; | ||
799 | int rc = 0; | ||
800 | int bytes_returned = 0; | ||
801 | __u16 params, param_offset, offset, byte_count; | ||
802 | |||
803 | cFYI(1, ("In POSIX delete")); | ||
804 | PsxDelete: | ||
805 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
806 | (void **) &pSMBr); | ||
807 | if (rc) | ||
808 | return rc; | ||
809 | |||
810 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
811 | name_len = | ||
812 | cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, | ||
813 | PATH_MAX, nls_codepage, remap); | ||
814 | name_len++; /* trailing null */ | ||
815 | name_len *= 2; | ||
816 | } else { /* BB add path length overrun check */ | ||
817 | name_len = strnlen(fileName, PATH_MAX); | ||
818 | name_len++; /* trailing null */ | ||
819 | strncpy(pSMB->FileName, fileName, name_len); | ||
820 | } | ||
821 | |||
822 | params = 6 + name_len; | ||
823 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
824 | pSMB->MaxDataCount = 0; /* BB double check this with jra */ | ||
825 | pSMB->MaxSetupCount = 0; | ||
826 | pSMB->Reserved = 0; | ||
827 | pSMB->Flags = 0; | ||
828 | pSMB->Timeout = 0; | ||
829 | pSMB->Reserved2 = 0; | ||
830 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | ||
831 | InformationLevel) - 4; | ||
832 | offset = param_offset + params; | ||
833 | |||
834 | /* Setup pointer to Request Data (inode type) */ | ||
835 | pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset); | ||
836 | pRqD->type = cpu_to_le16(type); | ||
837 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
838 | pSMB->DataOffset = cpu_to_le16(offset); | ||
839 | pSMB->SetupCount = 1; | ||
840 | pSMB->Reserved3 = 0; | ||
841 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); | ||
842 | byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq); | ||
843 | |||
844 | pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq)); | ||
845 | pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq)); | ||
846 | pSMB->ParameterCount = cpu_to_le16(params); | ||
847 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
848 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); | ||
849 | pSMB->Reserved4 = 0; | ||
850 | pSMB->hdr.smb_buf_length += byte_count; | ||
851 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
852 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
853 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
854 | if (rc) { | ||
855 | cFYI(1, ("Posix delete returned %d", rc)); | ||
856 | } | ||
857 | cifs_buf_release(pSMB); | ||
858 | |||
859 | cifs_stats_inc(&tcon->num_deletes); | ||
860 | |||
861 | if (rc == -EAGAIN) | ||
862 | goto PsxDelete; | ||
863 | |||
864 | return rc; | ||
865 | } | ||
866 | |||
867 | int | ||
792 | CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 868 | CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, |
793 | const struct nls_table *nls_codepage, int remap) | 869 | const struct nls_table *nls_codepage, int remap) |
794 | { | 870 | { |
@@ -933,7 +1009,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags, | |||
933 | int name_len; | 1009 | int name_len; |
934 | int rc = 0; | 1010 | int rc = 0; |
935 | int bytes_returned = 0; | 1011 | int bytes_returned = 0; |
936 | char *data_offset; | ||
937 | __u16 params, param_offset, offset, byte_count, count; | 1012 | __u16 params, param_offset, offset, byte_count, count; |
938 | OPEN_PSX_REQ * pdata; | 1013 | OPEN_PSX_REQ * pdata; |
939 | OPEN_PSX_RSP * psx_rsp; | 1014 | OPEN_PSX_RSP * psx_rsp; |
@@ -969,7 +1044,6 @@ PsxCreat: | |||
969 | param_offset = offsetof(struct smb_com_transaction2_spi_req, | 1044 | param_offset = offsetof(struct smb_com_transaction2_spi_req, |
970 | InformationLevel) - 4; | 1045 | InformationLevel) - 4; |
971 | offset = param_offset + params; | 1046 | offset = param_offset + params; |
972 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
973 | pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); | 1047 | pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); |
974 | pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; | 1048 | pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; |
975 | pdata->Permissions = cpu_to_le64(mode); | 1049 | pdata->Permissions = cpu_to_le64(mode); |
@@ -1671,7 +1745,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1671 | { | 1745 | { |
1672 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 1746 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
1673 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | 1747 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; |
1674 | char *data_offset; | ||
1675 | struct cifs_posix_lock *parm_data; | 1748 | struct cifs_posix_lock *parm_data; |
1676 | int rc = 0; | 1749 | int rc = 0; |
1677 | int timeout = 0; | 1750 | int timeout = 0; |
@@ -1698,8 +1771,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1698 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 1771 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; |
1699 | offset = param_offset + params; | 1772 | offset = param_offset + params; |
1700 | 1773 | ||
1701 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
1702 | |||
1703 | count = sizeof(struct cifs_posix_lock); | 1774 | count = sizeof(struct cifs_posix_lock); |
1704 | pSMB->MaxParameterCount = cpu_to_le16(2); | 1775 | pSMB->MaxParameterCount = cpu_to_le16(2); |
1705 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ | 1776 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ |
@@ -2120,9 +2191,7 @@ createSymLinkRetry: | |||
2120 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2191 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2121 | cifs_stats_inc(&tcon->num_symlinks); | 2192 | cifs_stats_inc(&tcon->num_symlinks); |
2122 | if (rc) { | 2193 | if (rc) { |
2123 | cFYI(1, | 2194 | cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc)); |
2124 | ("Send error in SetPathInfo (create symlink) = %d", | ||
2125 | rc)); | ||
2126 | } | 2195 | } |
2127 | 2196 | ||
2128 | if (pSMB) | 2197 | if (pSMB) |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a1ca55650505..cfa5b360d12e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -620,9 +620,21 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
620 | FreeXid(xid); | 620 | FreeXid(xid); |
621 | return -ENOMEM; | 621 | return -ENOMEM; |
622 | } | 622 | } |
623 | rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, | 623 | |
624 | if ((pTcon->ses->capabilities & CAP_UNIX) && | ||
625 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | ||
626 | le64_to_cpu(pTcon->fsUnixInfo.Capability))) { | ||
627 | rc = CIFSPOSIXDelFile(xid, pTcon, full_path, | ||
628 | SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, | ||
624 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 629 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
630 | cFYI(1, ("posix del rc %d", rc)); | ||
631 | if ((rc == 0) || (rc == -ENOENT)) | ||
632 | goto psx_del_no_retry; | ||
633 | } | ||
625 | 634 | ||
635 | rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, | ||
636 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
637 | psx_del_no_retry: | ||
626 | if (!rc) { | 638 | if (!rc) { |
627 | if (direntry->d_inode) | 639 | if (direntry->d_inode) |
628 | drop_nlink(direntry->d_inode); | 640 | drop_nlink(direntry->d_inode); |