Commit e30dcf3a authored by Steve French's avatar Steve French

[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)
parent 3e87d803
...@@ -2,6 +2,8 @@ Version 1.37 ...@@ -2,6 +2,8 @@ Version 1.37
------------ ------------
Fix readdir caching when unlink removes file in current search buffer, 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. 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 Version 1.36
------------ ------------
......
...@@ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->clientCanCacheAll = FALSE; cifs_inode->clientCanCacheAll = FALSE;
cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; 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_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
INIT_LIST_HEAD(&cifs_inode->openFileList); INIT_LIST_HEAD(&cifs_inode->openFileList);
return &cifs_inode->vfs_inode; return &cifs_inode->vfs_inode;
} }
......
...@@ -1080,20 +1080,23 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, ...@@ -1080,20 +1080,23 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
return -EFAULT; return -EFAULT;
} }
} else { } else if (count != 0) {
/* No buffer */ /* No buffer */
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
return -EINVAL; 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->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); 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) if(wct == 14)
pSMB->ByteCount = cpu_to_le16(byte_count); 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 * pSMBW =
(struct smb_com_writex_req *)pSMB; (struct smb_com_writex_req *)pSMB;
pSMBW->ByteCount = cpu_to_le16(byte_count); pSMBW->ByteCount = cpu_to_le16(byte_count);
......
...@@ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
/* now that we found one valid file /* now that we found one valid file
handle no sense continuing to loop handle no sense continuing to loop
trying others, so break here */ trying others, so break here */
/* if(rc == -EINVAL) { if(rc == -EINVAL) {
int bytes_written; int bytes_written;
rc = CIFSSMBWrite(xid, pTcon, rc = CIFSSMBWrite(xid, pTcon,
nfid, 0, nfid, 0,
attrs->ia_size, attrs->ia_size,
&bytes_written, &bytes_written, NULL,
NULL, NULL, long_op); NULL, 1 /* 45 sec */);
} */ cFYI(1,("wrt seteof rc %d",rc));
}
break; break;
} }
} }
...@@ -1055,14 +1056,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1055,14 +1056,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
/* if(rc == -EINVAL) if(rc == -EINVAL) {
old_style_set_eof_via_write(xid, pTcon, __u16 netfid;
full_path, int oplock = FALSE;
attrs->ia_size,
cifs_sb->local_nls, 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_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);*/ 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 /* Server is ok setting allocation size implicitly - no need
...@@ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = vmtruncate(direntry->d_inode, attrs->ia_size); rc = vmtruncate(direntry->d_inode, attrs->ia_size);
cifs_truncate_page(direntry->d_inode->i_mapping, cifs_truncate_page(direntry->d_inode->i_mapping,
direntry->d_inode->i_size); direntry->d_inode->i_size);
} } else
goto cifs_setattr_exit;
} }
if (attrs->ia_valid & ATTR_UID) { 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; uid = attrs->ia_uid;
/* entry->uid = cpu_to_le16(attr->ia_uid); */
} }
if (attrs->ia_valid & ATTR_GID) { 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; gid = attrs->ia_gid;
/* entry->gid = cpu_to_le16(attr->ia_gid); */
} }
time_buf.Attributes = 0; time_buf.Attributes = 0;
if (attrs->ia_valid & ATTR_MODE) { 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; mode = attrs->ia_mode;
/* entry->mode = cpu_to_le16(attr->ia_mode); */
} }
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
...@@ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
} else } else
time_buf.LastWriteTime = 0; time_buf.LastWriteTime = 0;
/* 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 (attrs->ia_valid & ATTR_CTIME) { if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
set_time = TRUE; 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 = time_buf.ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
} else } else
time_buf.ChangeTime = 0; time_buf.ChangeTime = 0;
if (set_time || time_buf.Attributes) { 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 */ time_buf.CreationTime = 0; /* do not change */
/* In the future we should experiment - try setting timestamps /* In the future we should experiment - try setting timestamps
via Handle (SetFileInfo) instead of by path */ via Handle (SetFileInfo) instead of by path */
...@@ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
&time_buf, cifs_sb->local_nls); */ &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 /* do not need local check to inode_check_ok since the server does
that */ that */
if (!rc) if (!rc)
rc = inode_setattr(direntry->d_inode, attrs); rc = inode_setattr(direntry->d_inode, attrs);
cifs_setattr_exit:
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment