diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 3f5bc83dc3d..86b9dbbd844 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -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); + 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")); @@ -421,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; @@ -491,6 +497,8 @@ int cifs_get_inode_info(struct inode **pinode, /* BB add code here - validate if device or weird share or device type? */ } + + 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 */ @@ -501,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); @@ -829,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); @@ -1123,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; @@ -1239,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 @@ -1359,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; } @@ -1374,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 |