mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	[CIFS] Add support for legacy servers part eight. Write fixes for Windows
ME, and do not set ctime unless explicitly requested with atime and/or mtime (it gets thrown away by most servers anyway as there is no way to set this via posix). Signed-off-by: Steve French (sfrench@us.ibm.com)
This commit is contained in:
		
							parent
							
								
									3e87d80391
								
							
						
					
					
						commit
						e30dcf3a19
					
				
					 4 changed files with 66 additions and 31 deletions
				
			
		|  | @ -2,6 +2,8 @@ Version 1.37 | |||
| ------------ | ||||
| Fix readdir caching when unlink removes file in current search buffer, | ||||
| and this is followed by a rewind search to just before the deleted entry. | ||||
| Do not attempt to set ctime unless atime and/or mtime change requested | ||||
| (most servers throw it away anyway). | ||||
| 
 | ||||
| Version 1.36 | ||||
| ------------ | ||||
|  |  | |||
|  | @ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
| 	cifs_inode->clientCanCacheAll = FALSE; | ||||
| 	cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; | ||||
| 	cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */ | ||||
| 
 | ||||
| 	cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; | ||||
| 	INIT_LIST_HEAD(&cifs_inode->openFileList); | ||||
| 	return &cifs_inode->vfs_inode; | ||||
| } | ||||
|  |  | |||
|  | @ -1072,7 +1072,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) { | ||||
|  | @ -1080,20 +1080,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); | ||||
|  |  | |||
|  | @ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 					/* now that we found one valid file
 | ||||
| 					   handle no sense continuing to loop | ||||
| 					   trying others, so break here */ | ||||
| 					/* if(rc == -EINVAL) {
 | ||||
| 					if(rc == -EINVAL) { | ||||
| 						int bytes_written; | ||||
| 						rc = CIFSSMBWrite(xid, pTcon, | ||||
| 							nfid, 0, | ||||
| 							attrs->ia_size,  | ||||
| 							&bytes_written, | ||||
| 							NULL, NULL, long_op); | ||||
| 					} */ | ||||
| 							&bytes_written, NULL, | ||||
| 							NULL, 1 /* 45 sec */); | ||||
| 						cFYI(1,("wrt seteof rc %d",rc)); | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
|  | @ -1055,14 +1056,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 					   cifs_sb->local_nls,  | ||||
| 					   cifs_sb->mnt_cifs_flags & | ||||
| 						CIFS_MOUNT_MAP_SPECIAL_CHR); | ||||
| 			cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | ||||
| 			/* if(rc == -EINVAL)
 | ||||
| 				old_style_set_eof_via_write(xid, pTcon,  | ||||
| 						full_path,  | ||||
| 						attrs->ia_size, | ||||
| 						cifs_sb->local_nls, | ||||
| 						cifs_sb->mnt_cifs_flags & | ||||
| 						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/ | ||||
| 			cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); | ||||
| 			if(rc == -EINVAL) { | ||||
| 				__u16 netfid; | ||||
| 				int oplock = FALSE; | ||||
| 
 | ||||
| 				rc = SMBLegacyOpen(xid, pTcon, full_path, | ||||
| 					FILE_OPEN, | ||||
| 					SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||||
| 					CREATE_NOT_DIR, &netfid, &oplock, | ||||
| 					NULL, cifs_sb->local_nls, | ||||
| 					cifs_sb->mnt_cifs_flags & | ||||
| 						CIFS_MOUNT_MAP_SPECIAL_CHR); | ||||
| 				if (rc==0) { | ||||
| 					int bytes_written; | ||||
| 					rc = CIFSSMBWrite(xid, pTcon, | ||||
| 							netfid, 0, | ||||
| 							attrs->ia_size, | ||||
| 							&bytes_written, NULL, | ||||
| 							NULL, 1 /* 45 sec */); | ||||
| 					cFYI(1,("wrt seteof rc %d",rc)); | ||||
| 					CIFSSMBClose(xid, pTcon, netfid); | ||||
| 				} | ||||
| 
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* Server is ok setting allocation size implicitly - no need
 | ||||
|  | @ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 			rc = vmtruncate(direntry->d_inode, attrs->ia_size); | ||||
| 			cifs_truncate_page(direntry->d_inode->i_mapping, | ||||
| 					   direntry->d_inode->i_size); | ||||
| 		} | ||||
| 		} else  | ||||
| 			goto cifs_setattr_exit; | ||||
| 	} | ||||
| 	if (attrs->ia_valid & ATTR_UID) { | ||||
| 		cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | ||||
| 		cFYI(1, ("UID changed to %d", attrs->ia_uid)); | ||||
| 		uid = attrs->ia_uid; | ||||
| 		/* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||||
| 	} | ||||
| 	if (attrs->ia_valid & ATTR_GID) { | ||||
| 		cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | ||||
| 		cFYI(1, ("GID changed to %d", attrs->ia_gid)); | ||||
| 		gid = attrs->ia_gid; | ||||
| 		/* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||||
| 	} | ||||
| 
 | ||||
| 	time_buf.Attributes = 0; | ||||
| 	if (attrs->ia_valid & ATTR_MODE) { | ||||
| 		cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | ||||
| 		cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); | ||||
| 		mode = attrs->ia_mode; | ||||
| 		/* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||||
| 	} | ||||
| 
 | ||||
| 	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||||
|  | @ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||||
| 	} else | ||||
| 		time_buf.LastWriteTime = 0; | ||||
| 
 | ||||
| 	if (attrs->ia_valid & ATTR_CTIME) { | ||||
| 	/* Do not set ctime explicitly unless other time
 | ||||
| 	   stamps are changed explicitly (i.e. by utime() | ||||
| 	   since we would then have a mix of client and | ||||
| 	   server times */ | ||||
| 	    | ||||
| 	if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||||
| 		set_time = TRUE; | ||||
| 		cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | ||||
| 		/* Although Samba throws this field away
 | ||||
| 		it may be useful to Windows - but we do | ||||
| 		not want to set ctime unless some other | ||||
| 		timestamp is changing */ | ||||
| 		cFYI(1, ("CIFS - CTIME changed ")); | ||||
| 		time_buf.ChangeTime = | ||||
| 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||||
| 	} else | ||||
| 		time_buf.ChangeTime = 0; | ||||
| 
 | ||||
| 	if (set_time || time_buf.Attributes) { | ||||
| 		/* BB what if setting one attribute fails (such as size) but
 | ||||
| 		   time setting works? */ | ||||
| 		time_buf.CreationTime = 0;	/* do not change */ | ||||
| 		/* In the future we should experiment - try setting timestamps
 | ||||
| 		   via Handle (SetFileInfo) instead of by path */ | ||||
|  | @ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
|         	        		&time_buf, cifs_sb->local_nls); */ | ||||
| 			} | ||||
| 		} | ||||
| 		/* Even if error on time set, no sense failing the call if
 | ||||
| 		the server would set the time to a reasonable value anyway, | ||||
| 		and this check ensures that we are not being called from | ||||
| 		sys_utimes in which case we ought to fail the call back to | ||||
| 		the user when the server rejects the call */ | ||||
| 		if((rc) && (attrs->ia_valid && | ||||
| 			 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | ||||
| 			rc = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* do not need local check to inode_check_ok since the server does
 | ||||
| 	   that */ | ||||
| 	if (!rc) | ||||
| 		rc = inode_setattr(direntry->d_inode, attrs); | ||||
| cifs_setattr_exit: | ||||
| 	kfree(full_path); | ||||
| 	FreeXid(xid); | ||||
| 	return rc; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Steve French
						Steve French