[CIFS] Add support for legacy servers part eight. Write fixes for Windows
authorSteve French <sfrench@us.ibm.com>
Wed, 21 Sep 2005 03:49:16 +0000 (20:49 -0700)
committerSteve French <sfrench@us.ibm.com>
Wed, 21 Sep 2005 03:49:16 +0000 (20:49 -0700)
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)
fs/cifs/CHANGES
fs/cifs/cifsfs.c
fs/cifs/cifssmb.c
fs/cifs/inode.c

index 8b55e56cf1fec1308b181e05d203cf62acca35e2..47ae68b51847c34867eb2dc4b78377d97bdbd678 100644 (file)
@@ -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
 ------------
index 43fb2aafa528cee52e2b6feb826d32cf276c1a3e..f738c8b19e3b197262efa8f35f2e337eb3c9003c 100644 (file)
@@ -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;
 }
index 575b2281518d5942223cfd65d5e952f356663782..f72a61df3c68cb7cb6db3b7a5e740e5b923de47f 100644 (file)
@@ -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);
index 6e82e1ae03b492fcbf19de65b611139a5ec8fe55..ca3af4eafcb2f19834bb4c34c101e5caf95209e0 100644 (file)
@@ -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;