[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:
@@ -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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
/* 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1056,13 +1057,29 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
&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;
|
||||||
|
Reference in New Issue
Block a user