extern void _FreeXid(unsigned int);
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
- extern char *build_path_from_dentry(struct dentry *);
+ extern char *build_path_from_dentry(struct dentry *, const struct cifs_sb_info *cifs_sb);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern void renew_parental_timestamps(struct dentry *direntry);
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ ,
int * /* bytes returned */ , const int long_op);
+extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
+ struct smb_hdr * /* input */ , int hdr_len,
+ const char * /* SMB data to send */ , int data_len,
+ int * /* bytes returned */ , const int long_op);
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
extern int is_valid_oplock_break(struct smb_hdr *smb);
extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
const char *searchName, const struct nls_table *nls_codepage,
- __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map);
+ __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep);
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
__u16 searchHandle, struct cifs_search_info * psrch_inf);
int remap);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData);
+ extern int CIFSSMBSETFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+ __u64 cap);
+
extern int CIFSSMBQFSAttributeInfo(const int xid,
struct cifsTconInfo *tcon);
extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
extern 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 int long_op);
+ const char *buf,const int long_op);
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, __u64 * inode_number,
const struct nls_table *nls_codepage,
}
#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);
return rc;
}
+
+
#endif /* CIFS_EXPERIMENTAL */
int
if (rc) {
cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
} else { /* decode response */
-
+ #ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_ffirst);
+ #endif
/* BB fill in */
}
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;
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;
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;
if (rc == -EAGAIN)
goto findFirstRetry;
} else { /* decode response */
+ #ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_ffirst);
+ #endif
/* BB remember to free buffer if error BB */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if(rc == 0) {
} else
cFYI(1, ("FindNext returned = %d", rc));
} else { /* decode response */
+ #ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_fnext);
+ #endif
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if(rc == 0) {
if (rc) {
cERROR(1, ("Send error in FindClose = %d", rc));
}
+ #ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_fclose);
+ #endif
cifs_small_buf_release(pSMB);
/* Since session is dead, search handle closed on server already */
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,
}
down(&inode->i_sb->s_vfs_rename_sem);
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
up(&inode->i_sb->s_vfs_rename_sem);
if (full_path == NULL) {
FreeXid(xid);
those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
if (full_path == NULL) {
up(&pCifsFile->fh_sem);
FreeXid(xid);
pTcon = cifs_sb->tcon;
- /* cFYI(1,
- (" write %d bytes to offset %lld of %s", write_size,
- *poffset, file->f_dentry->d_name.name)); */
+ cFYI(1,(" write %d bytes to offset %lld of %s", write_size,
+ *poffset, file->f_dentry->d_name.name)); /* BB removeme BB */
if (file->private_data == NULL)
return -EBADF;
if (rc != 0)
break;
}
-
+#ifdef CIFS_EXPERIMENTAL
+ /* BB FIXME We can not sign across two buffers yet */
+ cERROR(1,("checking signing")); /* BB removeme BB */
+ if(pTcon->ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED) == 0)
+ rc = CIFSSMBWrite2(xid, pTcon,
+ open_file->netfid,
+ min_t(const int, cifs_sb->wsize,
+ write_size - total_written),
+ *poffset, &bytes_written,
+ write_data + total_written,
+ long_op);
+ } else
+ /* BB FIXME fixup indentation of line below */
+#endif
rc = CIFSSMBWrite(xid, pTcon,
open_file->netfid,
min_t(const int, cifs_sb->wsize,