]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/hfs/inode.c
Merge branch 'for-2.6.37/drivers' into for-linus
[karo-tx-linux.git] / fs / hfs / inode.c
index 14f5cb1b9fdcfcd10116d065535831af20a3603a..dffb4e996643557f04ae1c83292bd729ef5adada 100644 (file)
@@ -39,10 +39,19 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
 {
+       int ret;
+
        *pagep = NULL;
-       return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+       ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                hfs_get_block,
                                &HFS_I(mapping->host)->phys_size);
+       if (unlikely(ret)) {
+               loff_t isize = mapping->host->i_size;
+               if (pos + len > isize)
+                       vmtruncate(mapping->host, isize);
+       }
+
+       return ret;
 }
 
 static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
@@ -112,9 +121,24 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
+       ssize_t ret;
 
-       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+       ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
                                  offset, nr_segs, hfs_get_block, NULL);
+
+       /*
+        * In case of error extending write may have instantiated a few
+        * blocks outside i_size. Trim these off again.
+        */
+       if (unlikely((rw & WRITE) && ret < 0)) {
+               loff_t isize = i_size_read(inode);
+               loff_t end = offset + iov_length(iov, nr_segs);
+
+               if (end > isize)
+                       vmtruncate(inode, isize);
+       }
+
+       return ret;
 }
 
 static int hfs_writepages(struct address_space *mapping,
@@ -500,15 +524,17 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
        HFS_I(inode)->rsrc_inode = dir;
        HFS_I(dir)->rsrc_inode = inode;
        igrab(dir);
-       hlist_add_head(&inode->i_hash, &HFS_SB(dir->i_sb)->rsrc_inodes);
+       hlist_add_fake(&inode->i_hash);
        mark_inode_dirty(inode);
 out:
        d_add(dentry, inode);
        return NULL;
 }
 
-void hfs_clear_inode(struct inode *inode)
+void hfs_evict_inode(struct inode *inode)
 {
+       truncate_inode_pages(&inode->i_data, 0);
+       end_writeback(inode);
        if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) {
                HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
                iput(HFS_I(inode)->rsrc_inode);
@@ -588,13 +614,43 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
                        attr->ia_mode = inode->i_mode & ~S_IWUGO;
                attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;
        }
-       error = inode_setattr(inode, attr);
-       if (error)
-               return error;
 
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode)) {
+               error = vmtruncate(inode, attr->ia_size);
+               if (error)
+                       return error;
+       }
+
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
        return 0;
 }
 
+static int hfs_file_fsync(struct file *filp, int datasync)
+{
+       struct inode *inode = filp->f_mapping->host;
+       struct super_block * sb;
+       int ret, err;
+
+       /* sync the inode to buffers */
+       ret = write_inode_now(inode, 0);
+
+       /* sync the superblock to buffers */
+       sb = inode->i_sb;
+       if (sb->s_dirt) {
+               lock_super(sb);
+               sb->s_dirt = 0;
+               if (!(sb->s_flags & MS_RDONLY))
+                       hfs_mdb_commit(sb);
+               unlock_super(sb);
+       }
+       /* .. finally sync the buffers to disk */
+       err = sync_blockdev(sb->s_bdev);
+       if (!ret)
+               ret = err;
+       return ret;
+}
 
 static const struct file_operations hfs_file_operations = {
        .llseek         = generic_file_llseek,
@@ -604,7 +660,7 @@ static const struct file_operations hfs_file_operations = {
        .aio_write      = generic_file_aio_write,
        .mmap           = generic_file_mmap,
        .splice_read    = generic_file_splice_read,
-       .fsync          = file_fsync,
+       .fsync          = hfs_file_fsync,
        .open           = hfs_file_open,
        .release        = hfs_file_release,
 };