Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
[pandora-kernel.git] / fs / cifs / cifssmb.c
index b31158a..7d14f24 100644 (file)
@@ -951,56 +951,69 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 }
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
+int
+CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
             const int netfid, const unsigned int count,
-            const __u64 offset, unsigned int *nbytes, const char __user *buf,
+            const __u64 offset, unsigned int *nbytes, const char *buf,
             const int long_op)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
-       WRITE_RSP *pSMBr = NULL;
-       /*int bytes_returned;*/
-       unsigned bytes_sent;
+       int bytes_returned;
+       int smb_hdr_len;
+       __u32 bytes_sent;
        __u16 byte_count;
 
+       cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
        rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
-    
        if (rc)
                return rc;
-       
-       pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
-
        /* tcon and ses pointer are checked in smb_init */
        if (tcon->ses->server == NULL)
                return -ECONNABORTED;
 
-       pSMB->AndXCommand = 0xFF; /* none */
+       pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
-       bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
+
+       /* Can increase buffer size if buffer is big enough in some cases - ie 
+       can send more if LARGE_WRITE_X capability returned by the server and if
+       our buffer is big enough or if we convert to iovecs on socket writes
+       and eliminate the copy to the CIFS buffer */
+       if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+               bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
+       } else {
+               bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
+                        & ~0xFF;
+       }
+
        if (bytes_sent > count)
                bytes_sent = count;
-       pSMB->DataLengthHigh = 0;
        pSMB->DataOffset =
            cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 
-       byte_count = bytes_sent + 1 /* pad */ ;
-       pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
-       pSMB->DataLengthHigh = 0;
-       pSMB->hdr.smb_buf_length += byte_count;
+       byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
+       pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
+       pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
+       smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
+       pSMB->hdr.smb_buf_length += bytes_sent+1;
        pSMB->ByteCount = cpu_to_le16(byte_count);
 
-/*     rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
+       rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
+                         buf, bytes_sent, &bytes_returned, long_op);
        if (rc) {
-               cFYI(1, ("Send error in write2 (large write) = %d", rc));
+               cFYI(1, ("Send error in write = %d", rc));
                *nbytes = 0;
-       } else
-               *nbytes = le16_to_cpu(pSMBr->Count);
+       } else {
+               WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
+               *nbytes = le16_to_cpu(pSMBr->CountHigh);
+               *nbytes = (*nbytes) << 16;
+               *nbytes += le16_to_cpu(pSMBr->Count);
+       }
 
        cifs_small_buf_release(pSMB);
 
@@ -1009,6 +1022,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
        return rc;
 }
+
+
 #endif /* CIFS_EXPERIMENTAL */
 
 int
@@ -2416,7 +2431,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
              const char *searchName, 
              const struct nls_table *nls_codepage,
              __u16 *   pnetfid,
-             struct cifs_search_info * psrch_inf, int remap)
+             struct cifs_search_info * psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2443,7 +2458,7 @@ findFirstRetry:
                it got remapped to 0xF03A as if it were part of the
                directory name instead of a wildcard */
                name_len *= 2;
-               pSMB->FileName[name_len] = '\\';
+               pSMB->FileName[name_len] = dirsep;
                pSMB->FileName[name_len+1] = 0;
                pSMB->FileName[name_len+2] = '*';
                pSMB->FileName[name_len+3] = 0;
@@ -2457,7 +2472,7 @@ findFirstRetry:
                if(name_len > buffersize-header)
                        free buffer exit; BB */
                strncpy(pSMB->FileName, searchName, name_len);
-               pSMB->FileName[name_len] = '\\';
+               pSMB->FileName[name_len] = dirsep;
                pSMB->FileName[name_len+1] = '*';
                pSMB->FileName[name_len+2] = 0;
                name_len += 3;
@@ -3265,6 +3280,77 @@ QFSUnixRetry:
        return rc;
 }
 
+int
+CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
+{
+/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
+       TRANSACTION2_SETFSI_REQ *pSMB = NULL;
+       TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, param_offset, offset, byte_count;
+
+       cFYI(1, ("In SETFSUnixInfo"));
+SETFSUnixRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       params = 4;     /* 2 bytes zero followed by info level. */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+       offset = param_offset + params;
+
+       pSMB->MaxParameterCount = cpu_to_le16(4);
+       pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
+       byte_count = 1 /* pad */ + params + 12;
+
+       pSMB->DataCount = cpu_to_le16(12);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+
+       /* Params. */
+       pSMB->FileNum = 0;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
+
+       /* Data. */
+       pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
+       pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
+       pSMB->ClientUnixCap = cpu_to_le64(cap);
+
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
+       } else {                /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               if (rc) {
+                       rc = -EIO;      /* bad smb */
+               }
+       }
+       cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto SETFSUnixRetry;
+
+       return rc;
+}
+
+
 
 int
 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,