gfs2: Dirty source inode during rename
authorAndreas Gruenbacher <agruenba@redhat.com>
Wed, 28 Feb 2018 19:48:53 +0000 (12:48 -0700)
committerBob Peterson <rpeterso@redhat.com>
Thu, 8 Mar 2018 16:26:20 +0000 (09:26 -0700)
Mark the source inode dirty during a rename instead of just updating the
underlying buffer head.  Otherwise, fsync may find the inode clean and
will then skip flushing the journal.  A subsequent power failure will
cause the rename to be lost.  This happens in command sequences like:

  xfs_io -f -c 'pwrite 0 4096' -c 'fsync' foo
  mv foo bar
  xfs_io -c 'fsync' bar
  # power failure

Fixes xfstests generic/322, generic/376.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
fs/gfs2/dir.c
fs/gfs2/inode.c

index 7c21aea0266b72c8745012a8f1b281db4fac80e7..d9fb0ad6cc30cc92c32e22b1c86ea056cad732b7 100644 (file)
@@ -1940,7 +1940,6 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
 {
        struct buffer_head *bh;
        struct gfs2_dirent *dent;
-       int error;
 
        dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);
        if (!dent) {
@@ -1953,18 +1952,10 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
        gfs2_trans_add_meta(dip->i_gl, bh);
        gfs2_inum_out(nip, dent);
        dent->de_type = cpu_to_be16(new_type);
-
-       if (dip->i_diskflags & GFS2_DIF_EXHASH) {
-               brelse(bh);
-               error = gfs2_meta_inode_buffer(dip, &bh);
-               if (error)
-                       return error;
-               gfs2_trans_add_meta(dip->i_gl, bh);
-       }
+       brelse(bh);
 
        dip->i_inode.i_mtime = dip->i_inode.i_ctime = current_time(&dip->i_inode);
-       gfs2_dinode_out(dip, bh->b_data);
-       brelse(bh);
+       mark_inode_dirty_sync(&dip->i_inode);
        return 0;
 }
 
index 59e0560180ec8971b0e8dd3915805ddf53c5342c..8700eb81563829dd69929d5ad292e9ae1cbc7816 100644 (file)
@@ -1326,19 +1326,11 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
 static int update_moved_ino(struct gfs2_inode *ip, struct gfs2_inode *ndip,
                            int dir_rename)
 {
-       int error;
-       struct buffer_head *dibh;
-
        if (dir_rename)
                return gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);
 
-       error = gfs2_meta_inode_buffer(ip, &dibh);
-       if (error)
-               return error;
        ip->i_inode.i_ctime = current_time(&ip->i_inode);
-       gfs2_trans_add_meta(ip->i_gl, dibh);
-       gfs2_dinode_out(ip, dibh->b_data);
-       brelse(dibh);
+       mark_inode_dirty_sync(&ip->i_inode);
        return 0;
 }