diff options
| author | Jeff Layton <jlayton@redhat.com> | 2009-07-09 20:02:50 -0400 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2009-07-09 17:15:10 -0400 |
| commit | 3bbeeb3c93a961bd01b969dd4395ecac0c09db8d (patch) | |
| tree | 57f003be4cb7a78094a3806df463844371329a85 | |
| parent | 654cf14ac0a71c56c1f0032140c3403382ca076b (diff) | |
cifs: add and use CIFSSMBUnixSetFileInfo for setattr calls
cifs: add and use CIFSSMBUnixSetFileInfo for setattr calls
When there's an open filehandle, SET_FILE_INFO is apparently preferred
over SET_PATH_INFO. Add a new variant that sets a FILE_UNIX_INFO_BASIC
infolevel via SET_FILE_INFO and switch cifs_setattr_unix to use the
new call when there's an open filehandle available.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 63 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 11 |
3 files changed, 77 insertions, 1 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d95fd427de57..37c11c08c529 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -220,6 +220,10 @@ struct cifs_unix_set_info_args { | |||
| 220 | dev_t device; | 220 | dev_t device; |
| 221 | }; | 221 | }; |
| 222 | 222 | ||
| 223 | extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, | ||
| 224 | const struct cifs_unix_set_info_args *args, | ||
| 225 | u16 fid, u32 pid_of_opener); | ||
| 226 | |||
| 223 | extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon, | 227 | extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon, |
| 224 | char *fileName, | 228 | char *fileName, |
| 225 | const struct cifs_unix_set_info_args *args, | 229 | const struct cifs_unix_set_info_args *args, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1f3c8a463fcd..922f5fe2084c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -5116,6 +5116,69 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | |||
| 5116 | } | 5116 | } |
| 5117 | 5117 | ||
| 5118 | int | 5118 | int |
| 5119 | CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, | ||
| 5120 | const struct cifs_unix_set_info_args *args, | ||
| 5121 | u16 fid, u32 pid_of_opener) | ||
| 5122 | { | ||
| 5123 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | ||
| 5124 | FILE_UNIX_BASIC_INFO *data_offset; | ||
| 5125 | int rc = 0; | ||
| 5126 | u16 params, param_offset, offset, byte_count, count; | ||
| 5127 | |||
| 5128 | cFYI(1, ("Set Unix Info (via SetFileInfo)")); | ||
| 5129 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | ||
| 5130 | |||
| 5131 | if (rc) | ||
| 5132 | return rc; | ||
| 5133 | |||
| 5134 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | ||
| 5135 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | ||
| 5136 | |||
| 5137 | params = 6; | ||
| 5138 | pSMB->MaxSetupCount = 0; | ||
| 5139 | pSMB->Reserved = 0; | ||
| 5140 | pSMB->Flags = 0; | ||
| 5141 | pSMB->Timeout = 0; | ||
| 5142 | pSMB->Reserved2 = 0; | ||
| 5143 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | ||
| 5144 | offset = param_offset + params; | ||
| 5145 | |||
| 5146 | data_offset = (FILE_UNIX_BASIC_INFO *) | ||
| 5147 | ((char *)(&pSMB->hdr.Protocol) + offset); | ||
| 5148 | count = sizeof(FILE_UNIX_BASIC_INFO); | ||
| 5149 | |||
| 5150 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
| 5151 | /* BB find max SMB PDU from sess */ | ||
| 5152 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 5153 | pSMB->SetupCount = 1; | ||
| 5154 | pSMB->Reserved3 = 0; | ||
| 5155 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | ||
| 5156 | byte_count = 3 /* pad */ + params + count; | ||
| 5157 | pSMB->DataCount = cpu_to_le16(count); | ||
| 5158 | pSMB->ParameterCount = cpu_to_le16(params); | ||
| 5159 | pSMB->TotalDataCount = pSMB->DataCount; | ||
| 5160 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
| 5161 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
| 5162 | pSMB->DataOffset = cpu_to_le16(offset); | ||
| 5163 | pSMB->Fid = fid; | ||
| 5164 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | ||
| 5165 | pSMB->Reserved4 = 0; | ||
| 5166 | pSMB->hdr.smb_buf_length += byte_count; | ||
| 5167 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
| 5168 | |||
| 5169 | cifs_fill_unix_set_info(data_offset, args); | ||
| 5170 | |||
| 5171 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | ||
| 5172 | if (rc) | ||
| 5173 | cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc)); | ||
| 5174 | |||
| 5175 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
| 5176 | since file handle passed in no longer valid */ | ||
| 5177 | |||
| 5178 | return rc; | ||
| 5179 | } | ||
| 5180 | |||
| 5181 | int | ||
| 5119 | CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | 5182 | CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, |
| 5120 | const struct cifs_unix_set_info_args *args, | 5183 | const struct cifs_unix_set_info_args *args, |
| 5121 | const struct nls_table *nls_codepage, int remap) | 5184 | const struct nls_table *nls_codepage, int remap) |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ad19007ea05f..55b616bb381e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1790,6 +1790,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1790 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1790 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 1791 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 1791 | struct cifsTconInfo *pTcon = cifs_sb->tcon; |
| 1792 | struct cifs_unix_set_info_args *args = NULL; | 1792 | struct cifs_unix_set_info_args *args = NULL; |
| 1793 | struct cifsFileInfo *open_file; | ||
| 1793 | 1794 | ||
| 1794 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", | 1795 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", |
| 1795 | direntry->d_name.name, attrs->ia_valid)); | 1796 | direntry->d_name.name, attrs->ia_valid)); |
| @@ -1876,10 +1877,18 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1876 | args->ctime = NO_CHANGE_64; | 1877 | args->ctime = NO_CHANGE_64; |
| 1877 | 1878 | ||
| 1878 | args->device = 0; | 1879 | args->device = 0; |
| 1879 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 1880 | open_file = find_writable_file(cifsInode); |
| 1881 | if (open_file) { | ||
| 1882 | u16 nfid = open_file->netfid; | ||
| 1883 | u32 npid = open_file->pid; | ||
| 1884 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | ||
| 1885 | atomic_dec(&open_file->wrtPending); | ||
| 1886 | } else { | ||
| 1887 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | ||
| 1880 | cifs_sb->local_nls, | 1888 | cifs_sb->local_nls, |
| 1881 | cifs_sb->mnt_cifs_flags & | 1889 | cifs_sb->mnt_cifs_flags & |
| 1882 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1890 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1891 | } | ||
| 1883 | 1892 | ||
| 1884 | if (!rc) | 1893 | if (!rc) |
| 1885 | rc = inode_setattr(inode, attrs); | 1894 | rc = inode_setattr(inode, attrs); |
