]> err.no Git - linux-2.6/blobdiff - fs/cifs/cifssmb.c
[PATCH] libata: implement per-dev EH action mask eh_info->dev_action[]
[linux-2.6] / fs / cifs / cifssmb.c
index e567f4e6196aa1a5348294c810e939455b385282..925881e00ff210e08822cc456337be1734f801d8 100644 (file)
@@ -1352,6 +1352,115 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        return rc;
 }
 
+int
+CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+               const __u16 smb_file_id, const int get_flag, const __u64 len,
+               struct file_lock *pLockData, const __u16 lock_type, 
+               const int waitFlag)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+       char *data_offset;
+       struct cifs_posix_lock *parm_data;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, param_offset, offset, byte_count, count;
+
+       cFYI(1, ("Posix Lock"));
+
+       if(pLockData == NULL)
+               return EINVAL;
+
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
+       params = 6; 
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+       count = sizeof(struct cifs_posix_lock);
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       if(get_flag)
+               pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+       else
+               pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+       byte_count = 3 /* pad */  + params + count;
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       parm_data = (struct cifs_posix_lock *) 
+                       (((char *) &pSMB->hdr.Protocol) + offset);
+
+       parm_data->lock_type = cpu_to_le16(lock_type);
+       if(waitFlag)
+               parm_data->lock_flags = cpu_to_le16(1);
+       parm_data->pid = cpu_to_le32(current->tgid);
+       parm_data->start = cpu_to_le64(pLockData->fl_start);
+       parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
+
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = smb_file_id;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
+       pSMB->Reserved4 = 0;
+       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 Posix Lock = %d", rc));
+       } else if (get_flag) {
+               /* lock structure can be returned on get */
+               __u16 data_offset;
+               __u16 data_count;
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+               if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
+                       rc = -EIO;      /* bad smb */
+                       goto plk_err_exit;
+               }
+               if(pLockData == NULL) {
+                       rc = -EINVAL;
+                       goto plk_err_exit;
+               }
+               data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+               data_count  = le16_to_cpu(pSMBr->t2.DataCount);
+               if(data_count < sizeof(struct cifs_posix_lock)) {
+                       rc = -EIO;
+                       goto plk_err_exit;
+               }
+               parm_data = (struct cifs_posix_lock *)
+                       ((char *)&pSMBr->hdr.Protocol + data_offset);
+               if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
+                       pLockData->fl_type = F_UNLCK;
+       }
+plk_err_exit:
+       if (pSMB)
+               cifs_small_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
 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 {
@@ -2982,7 +3091,8 @@ findFirstRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(
-         offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+             offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
+               - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
@@ -3005,12 +3115,12 @@ findFirstRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_ffirst);
 
-       if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+       if (rc) {/* BB add logic to retry regular search if Unix search
+                       rejected unexpectedly by server */
                /* BB Add code to handle unsupported level rc */
                cFYI(1, ("Error in FindFirst = %d", rc));
 
-               if (pSMB)
-                       cifs_buf_release(pSMB);
+               cifs_buf_release(pSMB);
 
                /* BB eventually could optimize out free and realloc of buf */
                /*    for this case */
@@ -3026,6 +3136,7 @@ findFirstRetry:
                                psrch_inf->unicode = FALSE;
 
                        psrch_inf->ntwrk_buf_start = (char *)pSMBr;
+                       psrch_inf->smallBuf = 0;
                        psrch_inf->srch_entries_start = 
                                (char *) &pSMBr->hdr.Protocol + 
                                        le16_to_cpu(pSMBr->t2.DataOffset);
@@ -3038,7 +3149,7 @@ findFirstRetry:
                                psrch_inf->endOfSearch = FALSE;
 
                        psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
-                       psrch_inf->index_of_last_entry = 
+                       psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
                        *pnetfid = parms->SearchHandle;
                } else {
@@ -3146,9 +3257,14 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                        parms = (T2_FNEXT_RSP_PARMS *)response_data;
                        response_data = (char *)&pSMBr->hdr.Protocol +
                                le16_to_cpu(pSMBr->t2.DataOffset);
-                       cifs_buf_release(psrch_inf->ntwrk_buf_start);
+                       if(psrch_inf->smallBuf)
+                               cifs_small_buf_release(
+                                       psrch_inf->ntwrk_buf_start);
+                       else
+                               cifs_buf_release(psrch_inf->ntwrk_buf_start);
                        psrch_inf->srch_entries_start = response_data;
                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
+                       psrch_inf->smallBuf = 0;
                        if(parms->EndofSearch)
                                psrch_inf->endOfSearch = TRUE;
                        else
@@ -3862,6 +3978,7 @@ CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
 
        cFYI(1, ("In SETFSUnixInfo"));
 SETFSUnixRetry:
+       /* BB switch to small buf init to save memory */
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
@@ -4936,7 +5053,7 @@ SetEARetry:
        parm_data->list_len = cpu_to_le32(count);
        parm_data->list[0].EA_flags = 0;
        /* we checked above that name len is less than 255 */
-       parm_data->list[0].name_len = (__u8)name_len;;
+       parm_data->list[0].name_len = (__u8)name_len;
        /* EA names are always ASCII */
        if(ea_name)
                strncpy(parm_data->list[0].name,ea_name,name_len);