]> err.no Git - linux-2.6/blobdiff - fs/cifs/cifssmb.c
[PATCH] exportfs: add find_acceptable_alias helper
[linux-2.6] / fs / cifs / cifssmb.c
index 74733851cfad5f49e78cfc488475e1dca0916297..6867e556d37e51485a4e9d35fb7ea332fc971b6d 100644 (file)
@@ -90,6 +90,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
           check for tcp and smb session status done differently
           for those three - in the calling routine */
        if(tcon) {
+               if(tcon->tidStatus == CifsExiting) {
+                       /* only tree disconnect, open, and write,
+                       (and ulogoff which does not have tcon)
+                       are allowed as we start force umount */
+                       if((smb_command != SMB_COM_WRITE_ANDX) && 
+                          (smb_command != SMB_COM_OPEN_ANDX) && 
+                          (smb_command != SMB_COM_TREE_DISCONNECT)) {
+                               cFYI(1,("can not send cmd %d while umounting",
+                                       smb_command));
+                               return -ENODEV;
+                       }
+               }
                if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
                                  (tcon->ses->server)){
                        struct nls_table *nls_codepage;
@@ -125,6 +137,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);
 
@@ -184,6 +199,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
           check for tcp and smb session status done differently
           for those three - in the calling routine */
        if(tcon) {
+               if(tcon->tidStatus == CifsExiting) {
+                       /* only tree disconnect, open, and write,
+                         (and ulogoff which does not have tcon)
+                         are allowed as we start force umount */
+                       if((smb_command != SMB_COM_WRITE_ANDX) &&
+                          (smb_command != SMB_COM_OPEN_ANDX) &&
+                          (smb_command != SMB_COM_TREE_DISCONNECT)) {
+                               cFYI(1,("can not send cmd %d while umounting",
+                                       smb_command));
+                               return -ENODEV;
+                       }
+               }
+
                if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
                                  (tcon->ses->server)){
                        struct nls_table *nls_codepage;
@@ -220,6 +248,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);
 
@@ -766,7 +797,7 @@ OldOpenRetry:
         if(create_options & CREATE_OPTION_SPECIAL)
                 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
         else
-                pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
+                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
 
        /* if ((omode & S_IWUGO) == 0)
                pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
@@ -777,7 +808,9 @@ OldOpenRetry:
        /* BB FIXME BB */
 /*     pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
        /* BB FIXME END BB */
-       pSMB->OpenFunction = convert_disposition(openDisposition);
+
+       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;
 
@@ -806,10 +839,12 @@ OldOpenRetry:
                        pfile_info->LastAccessTime = 0; /* BB fixme */
                        pfile_info->LastWriteTime = 0; /* BB fixme */
                        pfile_info->ChangeTime = 0;  /* BB fixme */
-                       pfile_info->Attributes = pSMBr->FileAttributes; 
+                       pfile_info->Attributes =
+                               cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
                        /* the file_info buf is endian converted by caller */
-                       pfile_info->AllocationSize = pSMBr->EndOfFile;
-                       pfile_info->EndOfFile = pSMBr->EndOfFile;
+                       pfile_info->AllocationSize =
+                               cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
+                       pfile_info->EndOfFile = pfile_info->AllocationSize;
                        pfile_info->NumberOfLinks = cpu_to_le32(1);
                }
        }
@@ -923,81 +958,6 @@ openRetry:
        return rc;
 }
 
-int
-SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
-            const int netfid, unsigned int count,
-            const __u64 lseek, unsigned int *nbytes, char **buf)
-{
-       int rc = -EACCES;
-       READX_REQ *pSMB = NULL;
-       READ_RSP *pSMBr = NULL;
-       char *pReadData = NULL;
-       int bytes_returned;
-
-       cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
-
-       /* field is shorter in legacy read, only 16 bits */
-       if(count > 2048)
-               count = 2048;  /* BB FIXME make this configurable */
-
-       if(lseek > 0xFFFFFFFF)
-               return -EIO; /* can not read that far into file on old server */
-
-       *nbytes = 0;
-       rc = smb_init(SMB_COM_READ_ANDX, 10, 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->AndXCommand = 0xFF;       /* none */
-       pSMB->Fid = netfid;
-       pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-       pSMB->Remaining = 0;
-       pSMB->MaxCount = cpu_to_le16(count);
-       pSMB->Reserved = 0; /* Must Be Zero */
-       pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
-
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       cifs_stats_inc(&tcon->num_reads);
-       if (rc) {
-               cERROR(1, ("Send error in legacy read = %d", rc));
-       } else {
-               int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
-               data_length = data_length << 16;
-               data_length += le16_to_cpu(pSMBr->DataLength);
-               *nbytes = data_length;
-
-               /*check that DataLength would not go beyond end of SMB */
-               if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
-                       cFYI(1,("bad length %d for count %d",data_length,count));
-                       rc = -EIO;
-                       *nbytes = 0;
-               } else {
-                       pReadData = (char *) (&pSMBr->hdr.Protocol) +
-                                               le16_to_cpu(pSMBr->DataOffset);
-/*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
-                               cERROR(1,("Faulting on read rc = %d",rc));
-                               rc = -EFAULT;
-                       }*/ /* can not use copy_to_user when using page cache*/
-                       if(*buf)
-                               memcpy(*buf,pReadData,data_length);
-               }
-       }
-       if(*buf)
-               cifs_buf_release(pSMB);
-       else
-               *buf = (char *)pSMB;
-
-       /* Note: On -EAGAIN error only caller can retry on handle based calls
-               since file handle passed in no longer valid */
-       return rc;
-}
-
 /* If no buffer passed in, then caller wants to do the copy
        as in the case of readpages so the SMB buffer must be
        freed by the caller */
@@ -1012,11 +972,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;
@@ -1028,12 +993,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);
@@ -1129,7 +1105,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) {
@@ -1137,20 +1113,23 @@ 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->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 */
+       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);
@@ -1180,18 +1159,22 @@ 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);
+       /* BB removeme BB */
+       cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
+
+       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 */
@@ -1201,39 +1184,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;
@@ -1597,7 +1580,7 @@ createSymLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
+                   cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
                                  /* find define for this maxpathcomponent */
                                  , nls_codepage);
                name_len++;     /* trailing null */
@@ -1621,7 +1604,7 @@ createSymLinkRetry:
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len_target =
-                   cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
+                   cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
                                  /* find define for this maxpathcomponent */
                                  , nls_codepage);
                name_len_target++;      /* trailing null */
@@ -1847,7 +1830,7 @@ querySymLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+                   cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
                                  /* find define for this maxpathcomponent */
                                  , nls_codepage);
                name_len++;     /* trailing null */
@@ -1904,7 +1887,7 @@ querySymLinkRetry:
                                        min_t(const int, buflen,count) / 2);
                        /* BB FIXME investigate remapping reserved chars here */
                                cifs_strfromUCS_le(symlinkinfo,
-                                       (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
+                                       (__le16 *) ((char *)&pSMBr->hdr.Protocol +
                                                data_offset),
                                        name_len, nls_codepage);
                        } else {
@@ -1995,7 +1978,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                                                        reparse_buf->TargetNameOffset),
                                                        min(buflen/2, reparse_buf->TargetNameLen / 2)); 
                                        cifs_strfromUCS_le(symlinkinfo,
-                                               (wchar_t *) (reparse_buf->LinkNamesBuf + 
+                                               (__le16 *) (reparse_buf->LinkNamesBuf + 
                                                reparse_buf->TargetNameOffset),
                                                name_len, nls_codepage);
                                } else { /* ASCII names */
@@ -2027,9 +2010,9 @@ qreparse_out:
 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
 {
        /* u8 cifs fields do not need le conversion */
-       ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
-       ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
-       ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
+       ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
+       ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
+       ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
        /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
 
        return;
@@ -2081,7 +2064,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
        } else if(size > buflen) {
                return -ERANGE;
        } else /* buffer big enough */ {
-               local_acl->a_version = POSIX_ACL_XATTR_VERSION;
+               local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
                for(i = 0;i < count ;i++) {
                        cifs_convert_ace(&local_acl->a_entries[i],pACE);
                        pACE ++;
@@ -2095,14 +2078,14 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
 {
        __u16 rc = 0; /* 0 = ACL converted ok */
 
-       cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
-       cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
+       cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
+       cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
        /* BB is there a better way to handle the large uid? */
-       if(local_ace->e_id == -1) {
+       if(local_ace->e_id == cpu_to_le32(-1)) {
        /* Probably no need to le convert -1 on any arch but can not hurt */
                cifs_ace->cifs_uid = cpu_to_le64(-1);
        } else 
-               cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
+               cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
        return rc;
 }
@@ -2122,16 +2105,17 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl
 
        count = posix_acl_xattr_count((size_t)buflen);
        cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
-               count,buflen,local_acl->a_version));
-       if(local_acl->a_version != 2) {
-               cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
+               count, buflen, le32_to_cpu(local_acl->a_version)));
+       if(le32_to_cpu(local_acl->a_version) != 2) {
+               cFYI(1,("unknown POSIX ACL version %d",
+                    le32_to_cpu(local_acl->a_version)));
                return 0;
        }
        cifs_acl->version = cpu_to_le16(1);
        if(acl_type == ACL_TYPE_ACCESS) 
-               cifs_acl->access_entry_count = count;
+               cifs_acl->access_entry_count = cpu_to_le16(count);
        else if(acl_type == ACL_TYPE_DEFAULT)
-               cifs_acl->default_entry_count = count;
+               cifs_acl->default_entry_count = cpu_to_le16(count);
        else {
                cFYI(1,("unknown ACL type %d",acl_type));
                return 0;
@@ -2444,9 +2428,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 */
 
@@ -3001,7 +2987,6 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
        return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
@@ -3095,7 +3080,6 @@ GetInodeNumOut:
                goto GetInodeNumberRetry;
        return rc;
 }
-#endif /* CIFS_EXPERIMENTAL */
 
 int
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
@@ -3247,7 +3231,7 @@ getDFSRetry:
                                temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
                                        cifs_strfromUCS_le(*targetUNCs,
-                                               (wchar_t *) temp, name_len, nls_codepage);
+                                               (__le16 *) temp, name_len, nls_codepage);
                                } else {
                                        strncpy(*targetUNCs,temp,name_len);
                                }
@@ -3269,6 +3253,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)
 {
@@ -3290,7 +3360,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;
@@ -3313,17 +3383,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
@@ -3693,16 +3760,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);
                }
@@ -3748,7 +3815,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);
@@ -3756,7 +3823,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;
@@ -4138,7 +4205,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);
@@ -4253,20 +4320,26 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                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);
-               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);
+                                               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;