Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[powerpc.git] / fs / cifs / inode.c
index 35d54bb..86b9dbb 100644 (file)
@@ -90,6 +90,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                                (*pinode)->i_ino =
                                        (unsigned long)findData.UniqueId;
                        } /* note ino incremented to unique num in new_inode */
+                       if(sb->s_flags & MS_NOATIME)
+                               (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
+                               
                        insert_inode_hash(*pinode);
                }
 
@@ -140,10 +143,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                inode->i_gid = le64_to_cpu(findData.Gid);
                inode->i_nlink = le64_to_cpu(findData.Nlinks);
 
-               if (is_size_safe_to_change(cifsInfo)) {
+               spin_lock(&inode->i_lock);
+               if (is_size_safe_to_change(cifsInfo, end_of_file)) {
                /* can not safely change the file size here if the
                   client is writing to it due to potential races */
-
                        i_size_write(inode, end_of_file);
 
                /* blksize needs to be multiple of two. So safer to default to
@@ -159,6 +162,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                /* for this calculation */
                        inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
                }
+               spin_unlock(&inode->i_lock);
 
                if (num_of_bytes < end_of_file)
                        cFYI(1, ("allocation size less than end of file"));
@@ -318,6 +322,7 @@ int cifs_get_inode_info(struct inode **pinode,
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *tmp_path;
        char *buf = NULL;
+       int adjustTZ = FALSE;
 
        pTcon = cifs_sb->tcon;
        cFYI(1,("Getting info on %s", search_path));
@@ -348,6 +353,7 @@ int cifs_get_inode_info(struct inode **pinode,
                                        pfindData, cifs_sb->local_nls, 
                                        cifs_sb->mnt_cifs_flags &
                                          CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       adjustTZ = TRUE;
                }
                
        }
@@ -419,6 +425,8 @@ int cifs_get_inode_info(struct inode **pinode,
                                } else /* do we need cast or hash to ino? */
                                        (*pinode)->i_ino = inode_num;
                        } /* else ino incremented to unique num in new_inode*/
+                       if(sb->s_flags & MS_NOATIME)
+                               (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
                        insert_inode_hash(*pinode);
                }
                inode = *pinode;
@@ -444,6 +452,10 @@ int cifs_get_inode_info(struct inode **pinode,
                inode->i_ctime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
                cFYI(0, ("Attributes came in as 0x%x", attr));
+               if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
+                       inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
+                       inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
+               }
 
                /* set default mode. will override for dirs below */
                if (atomic_read(&cifsInfo->inUse) == 0)
@@ -485,8 +497,10 @@ int cifs_get_inode_info(struct inode **pinode,
                /* BB add code here -
                   validate if device or weird share or device type? */
                }
-               if (is_size_safe_to_change(cifsInfo)) {
-                       /* can not safely change the file size here if the
+               
+               spin_lock(&inode->i_lock);
+               if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
+                       /* can not safely shrink the file size here if the
                           client is writing to it due to potential races */
                        i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
 
@@ -495,6 +509,7 @@ int cifs_get_inode_info(struct inode **pinode,
                        inode->i_blocks = (512 - 1 + le64_to_cpu(
                                           pfindData->AllocationSize)) >> 9;
                }
+               spin_unlock(&inode->i_lock);
 
                inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
@@ -823,8 +838,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
        if (!rc) {
                drop_nlink(inode);
+               spin_lock(&direntry->d_inode->i_lock);
                i_size_write(direntry->d_inode,0);
                clear_nlink(direntry->d_inode);
+               spin_unlock(&direntry->d_inode->i_lock);
        }
 
        cifsInode = CIFS_I(direntry->d_inode);
@@ -885,10 +902,14 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
                        kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
                if (info_buf_source != NULL) {
                        info_buf_target = info_buf_source + 1;
-                       rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
-                               info_buf_source, cifs_sb_source->local_nls, 
-                               cifs_sb_source->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       if (pTcon->ses->capabilities & CAP_UNIX)
+                               rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
+                                       info_buf_source, 
+                                       cifs_sb_source->local_nls,
+                                       cifs_sb_source->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       /* else rc is still EEXIST so will fall through to
+                          unlink the target and retry rename */
                        if (rc == 0) {
                                rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
                                                info_buf_target,
@@ -937,7 +958,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
                                 cifs_sb_source->mnt_cifs_flags & 
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
                if (rc==0) {
-                       CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
+                       rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
                                              cifs_sb_source->local_nls, 
                                              cifs_sb_source->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1085,8 +1106,10 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        struct kstat *stat)
 {
        int err = cifs_revalidate(dentry);
-       if (!err)
+       if (!err) {
                generic_fillattr(dentry->d_inode, stat);
+               stat->blksize = CIFS_MAX_MSGSIZE;
+       }
        return err;
 }
 
@@ -1111,6 +1134,52 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
        return rc;
 }
 
+static int cifs_vmtruncate(struct inode * inode, loff_t offset)
+{
+       struct address_space *mapping = inode->i_mapping;
+       unsigned long limit;
+
+       spin_lock(&inode->i_lock);
+       if (inode->i_size < offset)
+               goto do_expand;
+       /*
+        * truncation of in-use swapfiles is disallowed - it would cause
+        * subsequent swapout to scribble on the now-freed blocks.
+        */
+       if (IS_SWAPFILE(inode)) {
+               spin_unlock(&inode->i_lock);
+               goto out_busy;
+       }
+       i_size_write(inode, offset);
+       spin_unlock(&inode->i_lock);
+       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+       truncate_inode_pages(mapping, offset);
+       goto out_truncate;
+
+do_expand:
+       limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+       if (limit != RLIM_INFINITY && offset > limit) {
+               spin_unlock(&inode->i_lock);
+               goto out_sig;
+       }
+       if (offset > inode->i_sb->s_maxbytes) {
+               spin_unlock(&inode->i_lock);
+               goto out_big;
+       }
+       i_size_write(inode, offset);
+       spin_unlock(&inode->i_lock);
+out_truncate:
+       if (inode->i_op && inode->i_op->truncate)
+               inode->i_op->truncate(inode);
+       return 0;
+out_sig:
+       send_sig(SIGXFSZ, current, 0);
+out_big:
+       return -EFBIG;
+out_busy:
+       return -ETXTBSY;
+}
+
 int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 {
        int xid;
@@ -1227,7 +1296,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                   */
 
                if (rc == 0) {
-                       rc = vmtruncate(direntry->d_inode, attrs->ia_size);
+                       rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
                        cifs_truncate_page(direntry->d_inode->i_mapping,
                                           direntry->d_inode->i_size);
                } else 
@@ -1347,7 +1416,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                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 &&
+               if((rc) && (attrs->ia_valid &
                         (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
                        rc = 0;
        }
@@ -1362,9 +1431,11 @@ cifs_setattr_exit:
        return rc;
 }
 
+#if 0
 void cifs_delete_inode(struct inode *inode)
 {
        cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
        /* may have to add back in if and when safe distributed caching of
           directories added e.g. via FindNotify */
 }
+#endif