]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'gfs2/master'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 22 Sep 2011 02:42:52 +0000 (12:42 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 22 Sep 2011 02:42:52 +0000 (12:42 +1000)
fs/gfs2/acl.c
fs/gfs2/aops.c
fs/gfs2/dir.c
fs/gfs2/file.c
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/quota.c
fs/gfs2/super.c
fs/gfs2/xattr.c

index 34501b64bc47a416993677b641b30fe64a84d13c..65978d7885c863b896e7da2ca04062498c449ac2 100644 (file)
@@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
                iattr.ia_valid = ATTR_MODE;
                iattr.ia_mode = mode;
 
-               error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
+               error = gfs2_setattr_simple(inode, &iattr);
        }
 
        return error;
@@ -160,6 +160,7 @@ out:
 
 int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
 {
+       struct inode *inode = &ip->i_inode;
        struct posix_acl *acl;
        char *data;
        unsigned int len;
@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
        if (IS_ERR(acl))
                return PTR_ERR(acl);
        if (!acl)
-               return gfs2_setattr_simple(ip, attr);
+               return gfs2_setattr_simple(inode, attr);
 
        error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
        if (error)
index f9fbbe96c222860374840a825f2168d14b340f83..212fe74927ba7852ee5843291bdfa30dee627404 100644 (file)
@@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        u64 to = pos + copied;
        void *kaddr;
        unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
-       struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
 
        BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
        kaddr = kmap_atomic(page, KM_USER0);
@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        if (copied) {
                if (inode->i_size < to)
                        i_size_write(inode, to);
-               gfs2_dinode_out(ip, di);
                mark_inode_dirty(inode);
        }
 
@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
                gfs2_page_add_databufs(ip, page, from, to);
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
-       if (ret > 0) {
-               gfs2_dinode_out(ip, dibh->b_data);
-               mark_inode_dirty(inode);
-       }
 
        if (inode == sdp->sd_rindex) {
                adjust_fs_space(inode);
index 1cc2f8ec52a2cb76246eaba3ea08efac57bf0eae..898e62ed5b85f4685260d9b19bf15efe56d05365 100644 (file)
@@ -240,16 +240,15 @@ fail:
        return error;
 }
 
-static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
-                                u64 offset, unsigned int size)
+static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf,
+                                unsigned int size)
 {
        struct buffer_head *dibh;
        int error;
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (!error) {
-               offset += sizeof(struct gfs2_dinode);
-               memcpy(buf, dibh->b_data + offset, size);
+               memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size);
                brelse(dibh);
        }
 
@@ -261,13 +260,12 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
  * gfs2_dir_read_data - Read a data from a directory inode
  * @ip: The GFS2 Inode
  * @buf: The buffer to place result into
- * @offset: File offset to begin jdata_readng from
  * @size: Amount of data to transfer
  *
  * Returns: The amount of data actually copied or the error
  */
-static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
-                             unsigned int size, unsigned ra)
+static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
+                             unsigned int size)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        u64 lblock, dblock;
@@ -275,24 +273,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
        unsigned int o;
        int copied = 0;
        int error = 0;
-       u64 disksize = i_size_read(&ip->i_inode);
-
-       if (offset >= disksize)
-               return 0;
-
-       if (offset + size > disksize)
-               size = disksize - offset;
-
-       if (!size)
-               return 0;
 
        if (gfs2_is_stuffed(ip))
-               return gfs2_dir_read_stuffed(ip, buf, offset, size);
+               return gfs2_dir_read_stuffed(ip, buf, size);
 
        if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
                return -EINVAL;
 
-       lblock = offset;
+       lblock = 0;
        o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
 
        while (copied < size) {
@@ -311,8 +299,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
                        if (error || !dblock)
                                goto fail;
                        BUG_ON(extlen < 1);
-                       if (!ra)
-                               extlen = 1;
                        bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
                } else {
                        error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
@@ -328,7 +314,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
                extlen--;
                memcpy(buf, bh->b_data + o, amount);
                brelse(bh);
-               buf += amount;
+               buf += (amount/sizeof(__be64));
                copied += amount;
                lblock++;
                o = sizeof(struct gfs2_meta_header);
@@ -371,7 +357,7 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
        if (hc == NULL)
                return ERR_PTR(-ENOMEM);
 
-       ret = gfs2_dir_read_data(ip, (char *)hc, 0, hsize, 1);
+       ret = gfs2_dir_read_data(ip, hc, hsize);
        if (ret < 0) {
                kfree(hc);
                return ERR_PTR(ret);
@@ -1695,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
        const struct qstr *name = &dentry->d_name;
        struct gfs2_dirent *dent, *prev = NULL;
        struct buffer_head *bh;
-       int error;
 
        /* Returns _either_ the entry (if its first in block) or the
           previous entry otherwise */
@@ -1724,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
        }
        brelse(bh);
 
-       error = gfs2_meta_inode_buffer(dip, &bh);
-       if (error)
-               return error;
-
        if (!dip->i_entries)
                gfs2_consist_inode(dip);
-       gfs2_trans_add_bh(dip->i_gl, bh, 1);
        dip->i_entries--;
        dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
        if (S_ISDIR(dentry->d_inode->i_mode))
                drop_nlink(&dip->i_inode);
-       gfs2_dinode_out(dip, bh->b_data);
-       brelse(bh);
        mark_inode_dirty(&dip->i_inode);
 
-       return error;
+       return 0;
 }
 
 /**
index edeb9e80290382b39491d67c40ed3802535aac2b..d717b72500a47bab5adc85159666cbe7c894fd7b 100644 (file)
@@ -59,15 +59,24 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
        struct gfs2_holder i_gh;
        loff_t error;
 
-       if (origin == 2) {
+       switch (origin) {
+       case SEEK_END: /* These reference inode->i_size */
+       case SEEK_DATA:
+       case SEEK_HOLE:
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
                                           &i_gh);
                if (!error) {
                        error = generic_file_llseek_unlocked(file, offset, origin);
                        gfs2_glock_dq_uninit(&i_gh);
                }
-       } else
+               break;
+       case SEEK_CUR:
+       case SEEK_SET:
                error = generic_file_llseek_unlocked(file, offset, origin);
+               break;
+       default:
+               error = -EINVAL;
+       }
 
        return error;
 }
@@ -551,8 +560,16 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * @end: the end position in the file to sync
  * @datasync: set if we can ignore timestamp changes
  *
- * The VFS will flush data for us. We only need to worry
- * about metadata here.
+ * We split the data flushing here so that we don't wait for the data
+ * until after we've also sent the metadata to disk. Note that for
+ * data=ordered, we will write & wait for the data at the log flush
+ * stage anyway, so this is unlikely to make much of a difference
+ * except in the data=writeback case.
+ *
+ * If the fdatawrite fails due to any reason except -EIO, we will
+ * continue the remainder of the fsync, although we'll still report
+ * the error at the end. This is to match filemap_write_and_wait_range()
+ * behaviour.
  *
  * Returns: errno
  */
@@ -560,30 +577,38 @@ static int gfs2_close(struct inode *inode, struct file *file)
 static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
                      int datasync)
 {
-       struct inode *inode = file->f_mapping->host;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        struct gfs2_inode *ip = GFS2_I(inode);
-       int ret;
+       int ret, ret1 = 0;
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret)
-               return ret;
-       mutex_lock(&inode->i_mutex);
+       if (mapping->nrpages) {
+               ret1 = filemap_fdatawrite_range(mapping, start, end);
+               if (ret1 == -EIO)
+                       return ret1;
+       }
 
        if (datasync)
                sync_state &= ~I_DIRTY_SYNC;
 
        if (sync_state) {
+               mutex_lock(&inode->i_mutex);
                ret = sync_inode_metadata(inode, 1);
                if (ret) {
                        mutex_unlock(&inode->i_mutex);
                        return ret;
                }
+               if (gfs2_is_jdata(ip))
+                       filemap_write_and_wait(mapping);
                gfs2_ail_flush(ip->i_gl);
+               mutex_unlock(&inode->i_mutex);
        }
 
-       mutex_unlock(&inode->i_mutex);
-       return 0;
+       if (mapping->nrpages)
+               ret = filemap_fdatawait_range(mapping, start, end);
+
+       return ret ? ret : ret1;
 }
 
 /**
@@ -786,7 +811,6 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
                from = 0;
        }
 
-       gfs2_dinode_out(ip, dibh->b_data);
        mark_inode_dirty(inode);
 
        brelse(dibh);
index da21ecaafcc2725e4cbff9ee3a469f237f2e31b2..0cc3ff48ce20b9dcb497820cb63591875ee3bcc9 100644 (file)
 #include "trans.h"
 #include "dir.h"
 
+static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
+{
+       fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
+              bh, (unsigned long long)bh->b_blocknr, bh->b_state,
+              bh->b_page->mapping, bh->b_page->flags);
+       fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n",
+              gl->gl_name.ln_type, gl->gl_name.ln_number,
+              gfs2_glock2aspace(gl));
+       gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n");
+}
+
 /**
  * __gfs2_ail_flush - remove all buffers for a given lock from the AIL
  * @gl: the glock
  * None of the buffers should be dirty, locked, or pinned.
  */
 
-static void __gfs2_ail_flush(struct gfs2_glock *gl)
+static void __gfs2_ail_flush(struct gfs2_glock *gl, unsigned long b_state)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct list_head *head = &gl->gl_ail_list;
        struct gfs2_bufdata *bd;
        struct buffer_head *bh;
+       sector_t blocknr;
 
        spin_lock(&sdp->sd_ail_lock);
        while (!list_empty(head)) {
                bd = list_entry(head->next, struct gfs2_bufdata,
                                bd_ail_gl_list);
                bh = bd->bd_bh;
-               gfs2_remove_from_ail(bd);
-               bd->bd_bh = NULL;
+               blocknr = bh->b_blocknr;
+               if (bh->b_state & b_state)
+                       gfs2_ail_error(gl, bh);
                bh->b_private = NULL;
+               gfs2_remove_from_ail(bd); /* drops ref on bh */
                spin_unlock(&sdp->sd_ail_lock);
 
-               bd->bd_blkno = bh->b_blocknr;
+               bd->bd_bh = NULL;
+               bd->bd_blkno = blocknr;
+
                gfs2_log_lock(sdp);
-               gfs2_assert_withdraw(sdp, !buffer_busy(bh));
                gfs2_trans_add_revoke(sdp, bd);
                gfs2_log_unlock(sdp);
 
@@ -84,7 +99,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
        BUG_ON(current->journal_info);
        current->journal_info = &tr;
 
-       __gfs2_ail_flush(gl);
+       __gfs2_ail_flush(gl, (1ul << BH_Dirty)|(1ul << BH_Pinned)|(1ul << BH_Lock));
 
        gfs2_trans_end(sdp);
        gfs2_log_flush(sdp, NULL);
@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
        ret = gfs2_trans_begin(sdp, 0, revokes);
        if (ret)
                return;
-       __gfs2_ail_flush(gl);
+       __gfs2_ail_flush(gl, (1ul << BH_Dirty)|(1ul << BH_Pinned));
        gfs2_trans_end(sdp);
        gfs2_log_flush(sdp, NULL);
 }
index 892ac37de8aed8e272e491354c62352df93e690e..be5801a754060246ff9fca238797f3d30a9a59a2 100644 (file)
@@ -267,6 +267,7 @@ struct gfs2_alloc {
 enum {
        GIF_INVALID             = 0,
        GIF_QD_LOCKED           = 1,
+       GIF_ALLOC_FAILED        = 2,
        GIF_SW_PAGED            = 3,
 };
 
index 900cf986aadcc155d26028971f71bc6fa9a972ec..2af69056a9fd0729683525766a771d0900320445 100644 (file)
@@ -663,7 +663,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
 
 static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                             unsigned int mode, dev_t dev, const char *symname,
-                            unsigned int size)
+                            unsigned int size, int excl)
 {
        const struct qstr *name = &dentry->d_name;
        struct gfs2_holder ghs[2];
@@ -683,6 +683,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                goto fail;
 
        error = create_ok(dip, name, mode);
+       if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
+               inode = gfs2_lookupi(dir, &dentry->d_name, 0);
+               gfs2_glock_dq_uninit(ghs);
+               d_instantiate(dentry, inode);
+               return IS_ERR(inode) ? PTR_ERR(inode) : 0;
+       }
        if (error)
                goto fail_gunlock;
 
@@ -729,17 +735,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                gfs2_inplace_release(dip);
        gfs2_quota_unlock(dip);
        gfs2_alloc_put(dip);
-       gfs2_glock_dq_uninit_m(2, ghs);
        mark_inode_dirty(inode);
+       gfs2_glock_dq_uninit_m(2, ghs);
        d_instantiate(dentry, inode);
        return 0;
 
 fail_gunlock2:
        gfs2_glock_dq_uninit(ghs + 1);
-       if (inode && !IS_ERR(inode))
-               iput(inode);
 fail_gunlock:
        gfs2_glock_dq_uninit(ghs);
+       if (inode && !IS_ERR(inode)) {
+               set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
+               iput(inode);
+       }
 fail:
        if (bh)
                brelse(bh);
@@ -758,24 +766,10 @@ fail:
 static int gfs2_create(struct inode *dir, struct dentry *dentry,
                       int mode, struct nameidata *nd)
 {
-       struct inode *inode;
-       int ret;
-
-       for (;;) {
-               ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
-               if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
-                       return ret;
-
-               inode = gfs2_lookupi(dir, &dentry->d_name, 0);
-               if (inode) {
-                       if (!IS_ERR(inode))
-                               break;
-                       return PTR_ERR(inode);
-               }
-       }
-
-       d_instantiate(dentry, inode);
-       return 0;
+       int excl = 0;
+       if (nd && (nd->flags & LOOKUP_EXCL))
+               excl = 1;
+       return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
 }
 
 /**
@@ -924,8 +918,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        inc_nlink(&ip->i_inode);
        ip->i_inode.i_ctime = CURRENT_TIME;
-       gfs2_dinode_out(ip, dibh->b_data);
-       mark_inode_dirty(&ip->i_inode);
+       ihold(inode);
+       d_instantiate(dentry, inode);
+       mark_inode_dirty(inode);
 
 out_brelse:
        brelse(dibh);
@@ -947,11 +942,6 @@ out_child:
 out_parent:
        gfs2_holder_uninit(ghs);
        gfs2_holder_uninit(ghs + 1);
-       if (!error) {
-               ihold(inode);
-               d_instantiate(dentry, inode);
-               mark_inode_dirty(inode);
-       }
        return error;
 }
 
@@ -1024,8 +1014,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip,
                clear_nlink(inode);
        else
                drop_nlink(inode);
-       gfs2_trans_add_bh(ip->i_gl, bh, 1);
-       gfs2_dinode_out(ip, bh->b_data);
        mark_inode_dirty(inode);
        if (inode->i_nlink == 0)
                gfs2_unlink_di(inode);
@@ -1139,7 +1127,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
        if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
                return -ENAMETOOLONG;
 
-       return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size);
+       return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size, 0);
 }
 
 /**
@@ -1153,7 +1141,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
 
 static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-       return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0);
+       return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0, 0);
 }
 
 /**
@@ -1168,7 +1156,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
                      dev_t dev)
 {
-       return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0);
+       return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0);
 }
 
 /*
@@ -1563,21 +1551,10 @@ int gfs2_permission(struct inode *inode, int mask)
        return error;
 }
 
-static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+static int __gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
 {
-       struct inode *inode = &ip->i_inode;
-       struct buffer_head *dibh;
-       int error;
-
-       error = gfs2_meta_inode_buffer(ip, &dibh);
-       if (error)
-               return error;
-
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
-       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-       gfs2_dinode_out(ip, dibh->b_data);
-       brelse(dibh);
        return 0;
 }
 
@@ -1589,19 +1566,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
  * Returns: errno
  */
 
-int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+int gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
 {
        int error;
 
        if (current->journal_info)
-               return __gfs2_setattr_simple(ip, attr);
+               return __gfs2_setattr_simple(inode, attr);
 
-       error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
+       error = gfs2_trans_begin(GFS2_SB(inode), RES_DINODE, 0);
        if (error)
                return error;
 
-       error = __gfs2_setattr_simple(ip, attr);
-       gfs2_trans_end(GFS2_SB(&ip->i_inode));
+       error = __gfs2_setattr_simple(inode, attr);
+       gfs2_trans_end(GFS2_SB(inode));
        return error;
 }
 
@@ -1639,7 +1616,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
        if (error)
                goto out_gunlock_q;
 
-       error = gfs2_setattr_simple(ip, attr);
+       error = gfs2_setattr_simple(inode, attr);
        if (error)
                goto out_end_trans;
 
@@ -1695,12 +1672,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
        else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
                error = gfs2_acl_chmod(ip, attr);
        else
-               error = gfs2_setattr_simple(ip, attr);
+               error = gfs2_setattr_simple(inode, attr);
 
 out:
-       gfs2_glock_dq_uninit(&i_gh);
        if (!error)
                mark_inode_dirty(inode);
+       gfs2_glock_dq_uninit(&i_gh);
        return error;
 }
 
index 8d90e0c076722b42e2ed8da9fa40e65e2142e94f..276e7b52b6585d8755b991d6ee745f9dd7d982df 100644 (file)
@@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip);
 extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
                                  int is_root);
 extern int gfs2_permission(struct inode *inode, int mask);
-extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
+extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
 extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
 extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
 
index 0e8bb13381e446f358c3c9336df038cdecc435c7..3a9a9749f4968ab25d431bc19a5cbb0312f75600 100644 (file)
@@ -638,7 +638,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        unsigned long index = loc >> PAGE_CACHE_SHIFT;
        unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
        unsigned blocksize, iblock, pos;
-       struct buffer_head *bh, *dibh;
+       struct buffer_head *bh;
        struct page *page;
        void *kaddr, *ptr;
        struct gfs2_quota q, *qp;
@@ -736,22 +736,13 @@ get_a_page:
                goto get_a_page;
        }
 
-       /* Update the disk inode timestamp and size (if extended) */
-       err = gfs2_meta_inode_buffer(ip, &dibh);
-       if (err)
-               goto out;
-
        size = loc + sizeof(struct gfs2_quota);
        if (size > inode->i_size)
                i_size_write(inode, size);
        inode->i_mtime = inode->i_atime = CURRENT_TIME;
-       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-       gfs2_dinode_out(ip, dibh->b_data);
-       brelse(dibh);
        mark_inode_dirty(inode);
-
-out:
        return err;
+
 unlock_out:
        unlock_page(page);
        page_cache_release(page);
index b7beadd9ba4cfe5810c1747a566307878eca8204..b05fa59545500160436d467530dee381e694b2fc 100644 (file)
@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
        struct backing_dev_info *bdi = metamapping->backing_dev_info;
-       struct gfs2_holder gh;
+       int ret = 0;
+
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+       if (bdi->dirty_exceeded)
+               gfs2_ail1_flush(sdp, wbc);
+       else
+               filemap_fdatawrite(metamapping);
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               ret = filemap_fdatawait(metamapping);
+       if (ret)
+               mark_inode_dirty_sync(inode);
+       return ret;
+}
+
+/**
+ * gfs2_dirty_inode - check for atime updates
+ * @inode: The inode in question
+ * @flags: The type of dirty
+ *
+ * Unfortunately it can be called under any combination of inode
+ * glock and transaction lock, so we have to check carefully.
+ *
+ * At the moment this deals only with atime - it should be possible
+ * to expand that role in future, once a review of the locking has
+ * been carried out.
+ */
+
+static void gfs2_dirty_inode(struct inode *inode, int flags)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct buffer_head *bh;
-       struct timespec atime;
-       struct gfs2_dinode *di;
-       int ret = -EAGAIN;
-       int unlock_required = 0;
-
-       /* Skip timestamp update, if this is from a memalloc */
-       if (current->flags & PF_MEMALLOC)
-               goto do_flush;
+       struct gfs2_holder gh;
+       int need_unlock = 0;
+       int need_endtrans = 0;
+       int ret;
+
+       if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
+               return;
+
        if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
                ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
-               if (ret)
-                       goto do_flush;
-               unlock_required = 1;
+               if (ret) {
+                       fs_err(sdp, "dirty_inode: glock %d\n", ret);
+                       return;
+               }
+               need_unlock = 1;
        }
-       ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
-       if (ret)
-               goto do_unlock;
+
+       if (current->journal_info == NULL) {
+               ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
+               if (ret) {
+                       fs_err(sdp, "dirty_inode: gfs2_trans_begin %d\n", ret);
+                       goto out;
+               }
+               need_endtrans = 1;
+       }
+
        ret = gfs2_meta_inode_buffer(ip, &bh);
        if (ret == 0) {
-               di = (struct gfs2_dinode *)bh->b_data;
-               atime.tv_sec = be64_to_cpu(di->di_atime);
-               atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
-               if (timespec_compare(&inode->i_atime, &atime) > 0) {
-                       gfs2_trans_add_bh(ip->i_gl, bh, 1);
-                       gfs2_dinode_out(ip, bh->b_data);
-               }
+               gfs2_trans_add_bh(ip->i_gl, bh, 1);
+               gfs2_dinode_out(ip, bh->b_data);
                brelse(bh);
        }
-       gfs2_trans_end(sdp);
-do_unlock:
-       if (unlock_required)
+
+       if (need_endtrans)
+               gfs2_trans_end(sdp);
+out:
+       if (need_unlock)
                gfs2_glock_dq_uninit(&gh);
-do_flush:
-       if (wbc->sync_mode == WB_SYNC_ALL)
-               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
-       filemap_fdatawrite(metamapping);
-       if (bdi->dirty_exceeded)
-               gfs2_ail1_flush(sdp, wbc);
-       if (!ret && (wbc->sync_mode == WB_SYNC_ALL))
-               ret = filemap_fdatawait(metamapping);
-       if (ret)
-               mark_inode_dirty_sync(inode);
-       return ret;
 }
 
 /**
@@ -1471,9 +1497,11 @@ static void gfs2_evict_inode(struct inode *inode)
                goto out;
        }
 
-       error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
-       if (error)
-               goto out_truncate;
+       if (!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
+               error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
+               if (error)
+                       goto out_truncate;
+       }
 
        if (test_bit(GIF_INVALID, &ip->i_flags)) {
                error = gfs2_inode_refresh(ip);
@@ -1513,6 +1541,10 @@ static void gfs2_evict_inode(struct inode *inode)
        goto out_unlock;
 
 out_truncate:
+       gfs2_log_flush(sdp, ip->i_gl);
+       write_inode_now(inode, 1);
+       gfs2_ail_flush(ip->i_gl);
+
        /* Case 2 starts here */
        error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
        if (error)
@@ -1572,6 +1604,7 @@ const struct super_operations gfs2_super_ops = {
        .alloc_inode            = gfs2_alloc_inode,
        .destroy_inode          = gfs2_destroy_inode,
        .write_inode            = gfs2_write_inode,
+       .dirty_inode            = gfs2_dirty_inode,
        .evict_inode            = gfs2_evict_inode,
        .put_super              = gfs2_put_super,
        .sync_fs                = gfs2_sync_fs,
index 439b61c03262b767956e23f761b637e0b6905383..695304cf01cc672e7a1ce9d5036a1345a5a4f8ae 100644 (file)
@@ -1296,7 +1296,8 @@ fail:
 
 int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct inode *inode = &ip->i_inode;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct gfs2_ea_location el;
        int error;
 
@@ -1319,7 +1320,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
        if (error)
                return error;
 
-       error = gfs2_setattr_simple(ip, attr);
+       error = gfs2_setattr_simple(inode, attr);
        gfs2_trans_end(sdp);
        return error;
 }