Auto-update from upstream
[platform/kernel/linux-starfive.git] / fs / cifs / cifssmb.c
index 698cdce..9312bfc 100644 (file)
@@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
                                        , nls_codepage);
                                up(&tcon->ses->sesSem);
+                               /* BB FIXME add code to check if wsize needs
+                                  update due to negotiated smb buffer size
+                                  shrinking */
                                if(rc == 0)
                                        atomic_inc(&tconInfoReconnectCount);
 
@@ -220,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
                                up(&tcon->ses->sesSem);
+                               /* BB FIXME add code to check if wsize needs
+                               update due to negotiated smb buffer size
+                               shrinking */
                                if(rc == 0)
                                        atomic_inc(&tconInfoReconnectCount);
 
@@ -680,6 +686,150 @@ MkDirRetry:
        return rc;
 }
 
+static __u16 convert_disposition(int disposition)
+{
+       __u16 ofun = 0;
+
+       switch (disposition) {
+               case FILE_SUPERSEDE:
+                       ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+                       break;
+               case FILE_OPEN:
+                       ofun = SMBOPEN_OAPPEND;
+                       break;
+               case FILE_CREATE:
+                       ofun = SMBOPEN_OCREATE;
+                       break;
+               case FILE_OPEN_IF:
+                       ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
+                       break;
+               case FILE_OVERWRITE:
+                       ofun = SMBOPEN_OTRUNC;
+                       break;
+               case FILE_OVERWRITE_IF:
+                       ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+                       break;
+               default:
+                       cFYI(1,("unknown disposition %d",disposition));
+                       ofun =  SMBOPEN_OAPPEND; /* regular open */
+       }
+       return ofun;
+}
+
+int
+SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+           const char *fileName, const int openDisposition,
+           const int access_flags, const int create_options, __u16 * netfid,
+            int *pOplock, FILE_ALL_INFO * pfile_info,
+           const struct nls_table *nls_codepage, int remap)
+{
+       int rc = -EACCES;
+       OPENX_REQ *pSMB = NULL;
+       OPENX_RSP *pSMBr = NULL;
+       int bytes_returned;
+       int name_len;
+       __u16 count;
+
+OldOpenRetry:
+       rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       pSMB->AndXCommand = 0xFF;       /* none */
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               count = 1;      /* account for one byte pad to word boundary */
+               name_len =
+                  cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
+                                   fileName, PATH_MAX, nls_codepage, remap);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {                /* BB improve check for buffer overruns BB */
+               count = 0;      /* no pad */
+               name_len = strnlen(fileName, PATH_MAX);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->fileName, fileName, name_len);
+       }
+       if (*pOplock & REQ_OPLOCK)
+               pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
+       else if (*pOplock & REQ_BATCHOPLOCK) {
+               pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
+       }
+       pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
+       /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
+       /* 0 = read
+          1 = write
+          2 = rw
+          3 = execute
+        */
+       pSMB->Mode = cpu_to_le16(2);
+       pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
+       /* set file as system file if special file such
+          as fifo and server expecting SFU style and
+          no Unix extensions */
+
+        if(create_options & CREATE_OPTION_SPECIAL)
+                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+        else
+                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
+
+       /* if ((omode & S_IWUGO) == 0)
+               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
+       /*  Above line causes problems due to vfs splitting create into two
+           pieces - need to set mode after file created not while it is
+           being created */
+
+       /* BB FIXME BB */
+/*     pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
+       /* BB FIXME END BB */
+
+       pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
+       pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
+       count += name_len;
+       pSMB->hdr.smb_buf_length += count;
+
+       pSMB->ByteCount = cpu_to_le16(count);
+       /* long_op set to 1 to allow for oplock break timeouts */
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+       cifs_stats_inc(&tcon->num_opens);
+       if (rc) {
+               cFYI(1, ("Error in Open = %d", rc));
+       } else {
+       /* BB verify if wct == 15 */
+
+/*             *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
+
+               *netfid = pSMBr->Fid;   /* cifs fid stays in le */
+               /* Let caller know file was created so we can set the mode. */
+               /* Do we care about the CreateAction in any other cases? */
+       /* BB FIXME BB */
+/*             if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+                       *pOplock |= CIFS_CREATE_ACTION; */
+       /* BB FIXME END */
+
+               if(pfile_info) {
+                       pfile_info->CreationTime = 0; /* BB convert CreateTime*/
+                       pfile_info->LastAccessTime = 0; /* BB fixme */
+                       pfile_info->LastWriteTime = 0; /* BB fixme */
+                       pfile_info->ChangeTime = 0;  /* BB fixme */
+                       pfile_info->Attributes =
+                               cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
+                       /* the file_info buf is endian converted by caller */
+                       pfile_info->AllocationSize =
+                               cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
+                       pfile_info->EndOfFile = pfile_info->AllocationSize;
+                       pfile_info->NumberOfLinks = cpu_to_le32(1);
+               }
+       }
+
+       cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto OldOpenRetry;
+       return rc;
+}
+
 int
 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
@@ -797,11 +947,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        READ_RSP *pSMBr = NULL;
        char *pReadData = NULL;
        int bytes_returned;
+       int wct;
 
        cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+               wct = 12;
+       else
+               wct = 10; /* old style read */
 
        *nbytes = 0;
-       rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
+       rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
                return rc;
@@ -813,12 +968,23 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-       pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+       if(wct == 12)
+               pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+        else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+                return -EIO;
+
        pSMB->Remaining = 0;
        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
        pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
-       pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
-
+       if(wct == 12)
+               pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
+       else {
+               /* old style read */
+               struct smb_com_readx_req * pSMBW = 
+                       (struct smb_com_readx_req *)pSMB;
+               pSMBW->ByteCount = 0;   
+       }
+       
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_reads);
@@ -867,12 +1033,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
        WRITE_RSP *pSMBr = NULL;
-       int bytes_returned;
+       int bytes_returned, wct;
        __u32 bytes_sent;
        __u16 byte_count;
 
        /* cFYI(1,("write at %lld %d bytes",offset,count));*/
-       rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+       if(tcon->ses == NULL)
+               return -ECONNABORTED;
+
+       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+               wct = 14;
+       else
+               wct = 12;
+
+       rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
                return rc;
@@ -883,7 +1057,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+       if(wct == 14) 
+               pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+               return -EIO;
+       
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
@@ -902,7 +1080,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        if (bytes_sent > count)
                bytes_sent = count;
        pSMB->DataOffset =
-           cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+               cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
        if(buf)
            memcpy(pSMB->Data,buf,bytes_sent);
        else if(ubuf) {
@@ -910,17 +1088,27 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
                        cifs_buf_release(pSMB);
                        return -EFAULT;
                }
-       } else {
+       } else if (count != 0) {
                /* No buffer */
                cifs_buf_release(pSMB);
                return -EINVAL;
+       } /* else setting file size with write of zero bytes */
+       if(wct == 14)
+               byte_count = bytes_sent + 1; /* pad */
+       else /* wct == 12 */ {
+               byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
        }
-
-       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);
-       pSMB->hdr.smb_buf_length += bytes_sent+1;
-       pSMB->ByteCount = cpu_to_le16(byte_count);
+       pSMB->hdr.smb_buf_length += byte_count;
+
+       if(wct == 14)
+               pSMB->ByteCount = cpu_to_le16(byte_count);
+       else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
+               struct smb_com_writex_req * pSMBW = 
+                       (struct smb_com_writex_req *)pSMB;
+               pSMBW->ByteCount = cpu_to_le16(byte_count);
+       }
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
@@ -946,18 +1134,20 @@ CIFSSMBWrite(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 *buf,
-            const int long_op)
+            const __u64 offset, unsigned int *nbytes, struct kvec *iov,
+            int n_vec, const int long_op)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
-       int bytes_returned;
+       int bytes_returned, wct;
        int smb_hdr_len;
-       __u32 bytes_sent;
-       __u16 byte_count;
 
        cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
-       rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
+       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+               wct = 14;
+       else
+               wct = 12;
+       rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
        if (rc)
                return rc;
        /* tcon and ses pointer are checked in smb_init */
@@ -967,39 +1157,39 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+       if(wct == 14)
+               pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+               return -EIO;
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
 
-       /* 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->DataOffset =
            cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 
-       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);
+       pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
+       pSMB->DataLengthHigh = cpu_to_le16(count >> 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);
+       if(wct == 14)
+               pSMB->hdr.smb_buf_length += count+1;
+       else /* wct == 12 */
+               pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
+       if(wct == 14)
+               pSMB->ByteCount = cpu_to_le16(count + 1);
+       else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
+               struct smb_com_writex_req * pSMBW =
+                               (struct smb_com_writex_req *)pSMB;
+               pSMBW->ByteCount = cpu_to_le16(count + 5);
+       }
+       iov[0].iov_base = pSMB;
+       iov[0].iov_len = smb_hdr_len + 4;
 
-       rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
-                         buf, bytes_sent, &bytes_returned, long_op);
+       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
+                         long_op);
        cifs_stats_inc(&tcon->num_writes);
        if (rc) {
-               cFYI(1, ("Send error in write = %d", rc));
+               cFYI(1, ("Send error Write2 = %d", rc));
                *nbytes = 0;
        } else {
                WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
@@ -2210,9 +2400,11 @@ QInfRetry:
                cFYI(1, ("Send error in QueryInfo = %d", rc));
        } else if (pFinfo) {            /* decode response */
                memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
-               pFinfo->AllocationSize = (__le64) pSMBr->size;
-               pFinfo->EndOfFile = (__le64) pSMBr->size;
-               pFinfo->Attributes = (__le32) pSMBr->attr;
+               pFinfo->AllocationSize =
+                       cpu_to_le64(le32_to_cpu(pSMBr->size));
+               pFinfo->EndOfFile = pFinfo->AllocationSize;
+               pFinfo->Attributes =
+                       cpu_to_le32(le16_to_cpu(pSMBr->attr));
        } else
                rc = -EIO; /* bad buffer passed in */
 
@@ -3035,6 +3227,92 @@ GetDFSRefExit:
        return rc;
 }
 
+/* Query File System Info such as free space to old servers such as Win 9x */
+int
+SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+{
+/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
+       TRANSACTION2_QFSI_REQ *pSMB = NULL;
+       TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+       FILE_SYSTEM_ALLOC_INFO *response_data;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, byte_count;
+
+       cFYI(1, ("OldQFSInfo"));
+oldQFSInfoRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+               (void **) &pSMBr);
+       if (rc)
+               return rc;
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       params = 2;     /* level */
+       pSMB->TotalDataCount = 0;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       byte_count = params + 1 /* pad */ ;
+       pSMB->TotalParameterCount = cpu_to_le16(params);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(
+       struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+       pSMB->DataCount = 0;
+       pSMB->DataOffset = 0;
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+       pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
+       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) {
+               cFYI(1, ("Send error in QFSInfo = %d", rc));
+       } else {                /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+               if (rc || (pSMBr->ByteCount < 18))
+                       rc = -EIO;      /* bad smb */
+               else {
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                       cFYI(1,("qfsinf resp BCC: %d  Offset %d",
+                                pSMBr->ByteCount, data_offset));
+
+                       response_data =
+                               (FILE_SYSTEM_ALLOC_INFO *) 
+                               (((char *) &pSMBr->hdr.Protocol) + data_offset);
+                       FSData->f_bsize =
+                               le16_to_cpu(response_data->BytesPerSector) *
+                               le32_to_cpu(response_data->
+                                       SectorsPerAllocationUnit);
+                       FSData->f_blocks =
+                               le32_to_cpu(response_data->TotalAllocationUnits);
+                       FSData->f_bfree = FSData->f_bavail =
+                               le32_to_cpu(response_data->FreeAllocationUnits);
+                       cFYI(1,
+                            ("Blocks: %lld  Free: %lld Block size %ld",
+                             (unsigned long long)FSData->f_blocks,
+                             (unsigned long long)FSData->f_bfree,
+                             FSData->f_bsize));
+               }
+       }
+       cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto oldQFSInfoRetry;
+
+       return rc;
+}
+
 int
 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
 {
@@ -3056,7 +3334,7 @@ QFSInfoRetry:
        params = 2;     /* level */
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3079,17 +3357,14 @@ QFSInfoRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
-               cERROR(1, ("Send error in QFSInfo = %d", rc));
+               cFYI(1, ("Send error in QFSInfo = %d", rc));
        } else {                /* decode response */
                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
+               if (rc || (pSMBr->ByteCount < 24))
                        rc = -EIO;      /* bad smb */
                else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       cFYI(1,
-                               ("Decoding qfsinfo response.  BCC: %d  Offset %d",
-                               pSMBr->ByteCount, data_offset));
 
                        response_data =
                            (FILE_SYSTEM_INFO
@@ -3459,16 +3734,16 @@ QFSPosixRetry:
                                        le64_to_cpu(response_data->TotalBlocks);
                        FSData->f_bfree =
                            le64_to_cpu(response_data->BlocksAvail);
-                       if(response_data->UserBlocksAvail == -1) {
+                       if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
                                FSData->f_bavail = FSData->f_bfree;
                        } else {
                                FSData->f_bavail =
                                        le64_to_cpu(response_data->UserBlocksAvail);
                        }
-                       if(response_data->TotalFileNodes != -1)
+                       if(response_data->TotalFileNodes != cpu_to_le64(-1))
                                FSData->f_files =
                                        le64_to_cpu(response_data->TotalFileNodes);
-                       if(response_data->FreeFileNodes != -1)
+                       if(response_data->FreeFileNodes != cpu_to_le64(-1))
                                FSData->f_ffree =
                                        le64_to_cpu(response_data->FreeFileNodes);
                }
@@ -3514,7 +3789,7 @@ SetEOFRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
@@ -3522,7 +3797,7 @@ SetEOFRetry:
        params = 6 + name_len;
        data_count = sizeof (struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+       pSMB->MaxDataCount = cpu_to_le16(4100);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3904,7 +4179,7 @@ setPermsRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
@@ -3977,12 +4252,14 @@ setPermsRetry:
 }
 
 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
-                       const int notify_subdirs, const __u16 netfid,
-                       __u32 filter, const struct nls_table *nls_codepage)
+                 const int notify_subdirs, const __u16 netfid,
+                 __u32 filter, struct file * pfile, int multishot, 
+                 const struct nls_table *nls_codepage)
 {
        int rc = 0;
        struct smb_com_transaction_change_notify_req * pSMB = NULL;
        struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+       struct dir_notify_req *dnotify_req;
        int bytes_returned;
 
        cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
@@ -4015,6 +4292,28 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                        (struct smb_hdr *) pSMBr, &bytes_returned, -1);
        if (rc) {
                cFYI(1, ("Error in Notify = %d", rc));
+       } else {
+               /* Add file to outstanding requests */
+               /* BB change to kmem cache alloc */     
+               dnotify_req = (struct dir_notify_req *) kmalloc(
+                                               sizeof(struct dir_notify_req),
+                                                GFP_KERNEL);
+               if(dnotify_req) {
+                       dnotify_req->Pid = pSMB->hdr.Pid;
+                       dnotify_req->PidHigh = pSMB->hdr.PidHigh;
+                       dnotify_req->Mid = pSMB->hdr.Mid;
+                       dnotify_req->Tid = pSMB->hdr.Tid;
+                       dnotify_req->Uid = pSMB->hdr.Uid;
+                       dnotify_req->netfid = netfid;
+                       dnotify_req->pfile = pfile;
+                       dnotify_req->filter = filter;
+                       dnotify_req->multishot = multishot;
+                       spin_lock(&GlobalMid_Lock);
+                       list_add_tail(&dnotify_req->lhead, 
+                                       &GlobalDnotifyReqList);
+                       spin_unlock(&GlobalMid_Lock);
+               } else 
+                       rc = -ENOMEM;
        }
        cifs_buf_release(pSMB);
        return rc;