diff -urN unpatched/fs/cifs/cifspdu.h patched/fs/cifs/cifspdu.h --- unpatched/fs/cifs/cifspdu.h 2009-09-04 21:46:00.000000000 +0200 +++ patched/fs/cifs/cifspdu.h 2010-03-30 16:13:34.000000000 +0200 @@ -48,6 +48,7 @@ #define SMB_COM_RENAME 0x07 /* trivial response */ #define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */ #define SMB_COM_SETATTR 0x09 /* trivial response */ +#define SMB_COM_WRITE 0x0B #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ @@ -1007,6 +1008,20 @@ __u16 ByteCount; } __attribute__((packed)) WRITE_RSP; +typedef struct smb_com_legacy_write_req { + struct smb_hdr hdr; /* wct = 14 */ + __u16 Fid; + __u16 DataLength; + __u32 Offset; + __u16 Remaining; + __u16 ByteCount; +} __attribute__((packed)) LEGACY_WRITE_REQ; + +typedef struct smb_com_legacy_write_rsp { + struct smb_hdr hdr; /* wct = 6 */ + __le16 Count; +} __attribute__((packed)) LEGACY_WRITE_RSP; + /* legacy read request for older servers */ typedef struct smb_com_readx_req { struct smb_hdr hdr; /* wct = 10 */ diff -urN unpatched/fs/cifs/cifsproto.h patched/fs/cifs/cifsproto.h --- unpatched/fs/cifs/cifsproto.h 2009-09-04 21:46:00.000000000 +0200 +++ patched/fs/cifs/cifsproto.h 2010-03-30 18:54:39.000000000 +0200 @@ -335,6 +335,8 @@ const int netfid, const unsigned int count, const __u64 offset, unsigned int *nbytes, struct kvec *iov, const int nvec, const int long_op); +int CIFSSMBLegacyWrite0(const int xid, struct cifsTconInfo *tcon, + const int netfid, const __u64 offset); extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 *inode_number, const struct nls_table *nls_codepage, diff -urN unpatched/fs/cifs/cifssmb.c patched/fs/cifs/cifssmb.c --- unpatched/fs/cifs/cifssmb.c 2009-09-04 21:46:00.000000000 +0200 +++ patched/fs/cifs/cifssmb.c 2010-03-30 16:15:14.000000000 +0200 @@ -1562,6 +1562,49 @@ } int +CIFSSMBLegacyWrite0(const int xid, struct cifsTconInfo *tcon, + const int netfid, const __u64 offset) +{ + int rc = -EACCES; + LEGACY_WRITE_REQ *pSMB = NULL; + LEGACY_WRITE_RSP *pSMBr = NULL; + int bytes_returned; + + /* cFYI(1,("legacywrite at %lld %d bytes",offset,count));*/ + if (tcon->ses == NULL) + return -ECONNABORTED; + + rc = smb_init(SMB_COM_WRITE, 5, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; + + pSMB->Fid = netfid; + if ((offset >> 32) > 0) /* can not handle big offset for old srv */ + return -EIO; + pSMB->Offset = cpu_to_le32(offset & 0xFFFFFFFF); + pSMB->DataLength = 0; + pSMB->Remaining = 0; + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 1); + cifs_stats_inc(&tcon->num_writes); + if (rc) + cFYI(1, "Send error in legacy write = %d", rc); + + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 offset, unsigned int *nbytes, struct kvec *iov, diff -urN unpatched/fs/cifs/inode.c patched/fs/cifs/inode.c --- unpatched/fs/cifs/inode.c 2009-09-04 21:46:00.000000000 +0200 +++ patched/fs/cifs/inode.c 2010-03-30 18:56:08.000000000 +0200 @@ -1868,20 +1868,26 @@ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { __u16 netfid; int oplock = 0; + int open_disposition = (attrs->ia_size == 0) + ? FILE_OVERWRITE : FILE_OPEN; rc = SMBLegacyOpen(xid, pTcon, full_path, - FILE_OPEN, GENERIC_WRITE, + open_disposition, GENERIC_WRITE, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { - unsigned int bytes_written; - rc = CIFSSMBWrite(xid, pTcon, netfid, 0, - attrs->ia_size, - &bytes_written, NULL, - NULL, 1); - cFYI(1, "wrt seteof rc %d", rc); + if (open_disposition == FILE_OPEN) { + rc = CIFSSMBLegacyWrite0(xid, pTcon, + netfid, attrs->ia_size); + if (rc != 0) { + rc = CIFSSMBSetFileSize(xid, + pTcon, attrs->ia_size, + netfid, 0, false); + } + cFYI(1, "wrt seteof rc %d", rc); + } CIFSSMBClose(xid, pTcon, netfid); } }