diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
| -rw-r--r-- | fs/cifs/cifssmb.c | 35 | 
1 files changed, 33 insertions, 2 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 7cc7f83e931..5d3f29fef53 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -30,6 +30,7 @@  #include <linux/fs.h>  #include <linux/kernel.h>  #include <linux/vfs.h> +#include <linux/slab.h>  #include <linux/posix_acl_xattr.h>  #include <asm/uaccess.h>  #include "cifspdu.h" @@ -1430,6 +1431,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,  	__u32 bytes_sent;  	__u16 byte_count; +	*nbytes = 0; +  	/* cFYI(1, ("write at %lld %d bytes", offset, count));*/  	if (tcon->ses == NULL)  		return -ECONNABORTED; @@ -1512,11 +1515,18 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,  	cifs_stats_inc(&tcon->num_writes);  	if (rc) {  		cFYI(1, ("Send error in write = %d", rc)); -		*nbytes = 0;  	} else {  		*nbytes = le16_to_cpu(pSMBr->CountHigh);  		*nbytes = (*nbytes) << 16;  		*nbytes += le16_to_cpu(pSMBr->Count); + +		/* +		 * Mask off high 16 bits when bytes written as returned by the +		 * server is greater than bytes requested by the client. Some +		 * OS/2 servers are known to set incorrect CountHigh values. +		 */ +		if (*nbytes > count) +			*nbytes &= 0xFFFF;  	}  	cifs_buf_release(pSMB); @@ -1605,6 +1615,14 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,  		*nbytes = le16_to_cpu(pSMBr->CountHigh);  		*nbytes = (*nbytes) << 16;  		*nbytes += le16_to_cpu(pSMBr->Count); + +		/* +		 * Mask off high 16 bits when bytes written as returned by the +		 * server is greater than bytes requested by the client. OS/2 +		 * servers are known to set incorrect CountHigh values. +		 */ +		if (*nbytes > count) +			*nbytes &= 0xFFFF;  	}  /*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ @@ -1793,8 +1811,21 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,  		}  		parm_data = (struct cifs_posix_lock *)  			((char *)&pSMBr->hdr.Protocol + data_offset); -		if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK)) +		if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))  			pLockData->fl_type = F_UNLCK; +		else { +			if (parm_data->lock_type == +					__constant_cpu_to_le16(CIFS_RDLCK)) +				pLockData->fl_type = F_RDLCK; +			else if (parm_data->lock_type == +					__constant_cpu_to_le16(CIFS_WRLCK)) +				pLockData->fl_type = F_WRLCK; + +			pLockData->fl_start = parm_data->start; +			pLockData->fl_end = parm_data->start + +						parm_data->length - 1; +			pLockData->fl_pid = parm_data->pid; +		}  	}  plk_err_exit:  |