Merge tag 'gfs2-merge-window' of git://git.kernel.org:/pub/scm/linux/kernel/git/gfs2...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 27 Jun 2015 16:47:46 +0000 (09:47 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 27 Jun 2015 16:47:46 +0000 (09:47 -0700)
Pull GFS2 updates from Bob Peterson:
 "Here are the patches we've accumulated for GFS2 for the current
  upstream merge window.  We have a good mixture this time.  Here are
  some of the features:

   - Fix a problem with RO mounts writing to the journal.

   - Further improvements to quotas on GFS2.

   - Added support for rename2 and RENAME_EXCHANGE on GFS2.

   - Increase performance by making glock lru_list less of a bottleneck.

   - Increase performance by avoiding unnecessary buffer_head releases.

   - Increase performance by using average glock round trip time from all CPUs.

   - Fixes for some compiler warnings and minor white space issues.

   - Other misc bug fixes"

* tag 'gfs2-merge-window' of git://git.kernel.org:/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  GFS2: Don't brelse rgrp buffer_heads every allocation
  GFS2: Don't add all glocks to the lru
  gfs2: Don't support fallocate on jdata files
  gfs2: s64 cast for negative quota value
  gfs2: limit quota log messages
  gfs2: fix quota updates on block boundaries
  gfs2: fix shadow warning in gfs2_rbm_find()
  gfs2: kerneldoc warning fixes
  gfs2: convert simple_str to kstr
  GFS2: make sure S_NOSEC flag isn't overwritten
  GFS2: add support for rename2 and RENAME_EXCHANGE
  gfs2: handle NULL rgd in set_rgrp_preferences
  GFS2: inode.c: indent with TABs, not spaces
  GFS2: mark the journal idle to fix ro mounts
  GFS2: Average in only non-zero round-trip times for congestion stats
  GFS2: Use average srttb value in congestion calculations

1  2 
fs/gfs2/aops.c
fs/gfs2/file.c
fs/gfs2/inode.c
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c

diff --combined fs/gfs2/aops.c
@@@ -171,6 -171,7 +171,7 @@@ static int __gfs2_jdata_writepage(struc
  /**
   * gfs2_jdata_writepage - Write complete page
   * @page: Page to write
+  * @wbc: The writeback control
   *
   * Returns: errno
   *
@@@ -221,9 -222,10 +222,10 @@@ static int gfs2_writepages(struct addre
   * gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages
   * @mapping: The mapping
   * @wbc: The writeback control
-  * @writepage: The writepage function to call for each page
   * @pvec: The vector of pages
   * @nr_pages: The number of pages to write
+  * @end: End position
+  * @done_index: Page index
   *
   * Returns: non-zero if loop should terminate, zero otherwise
   */
@@@ -333,8 -335,6 +335,6 @@@ continue_unlock
   * gfs2_write_cache_jdata - Like write_cache_pages but different
   * @mapping: The mapping to write
   * @wbc: The writeback control
-  * @writepage: The writepage function to call
-  * @data: The data to pass to writepage
   *
   * The reason that we use our own function here is that we need to
   * start transactions before we grab page locks. This allows us
@@@ -588,6 -588,10 +588,10 @@@ int gfs2_internal_read(struct gfs2_inod
  
  /**
   * gfs2_readpages - Read a bunch of pages at once
+  * @file: The file to read from
+  * @mapping: Address space info
+  * @pages: List of pages to read
+  * @nr_pages: Number of pages to read
   *
   * Some notes:
   * 1. This is only for readahead, so we can simply ignore any things
@@@ -853,7 -857,7 +857,7 @@@ static int gfs2_stuffed_write_end(struc
   * @mapping: The address space to write to
   * @pos: The file position
   * @len: The length of the data
-  * @copied:
+  * @copied: How much was actually copied by the VFS
   * @page: The page that has been written
   * @fsdata: The fsdata (unused in GFS2)
   *
  /**
   * gfs2_ok_for_dio - check that dio is valid on this file
   * @ip: The inode
 - * @rw: READ or WRITE
   * @offset: The offset at which we are reading or writing
   *
   * Returns: 0 (to ignore the i/o request and thus fall back to buffered i/o)
   *          1 (to accept the i/o request)
   */
 -static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
 +static int gfs2_ok_for_dio(struct gfs2_inode *ip, loff_t offset)
  {
        /*
         * Should we return an error here? I can't see that O_DIRECT for
  
  
  
 -static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
 -                            struct iov_iter *iter, loff_t offset)
 +static ssize_t gfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 +                            loff_t offset)
  {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        rv = gfs2_glock_nq(&gh);
        if (rv)
                return rv;
 -      rv = gfs2_ok_for_dio(ip, rw, offset);
 +      rv = gfs2_ok_for_dio(ip, offset);
        if (rv != 1)
                goto out; /* dio not valid, fall back to buffered i/o */
  
                rv = filemap_write_and_wait_range(mapping, lstart, end);
                if (rv)
                        goto out;
 -              if (rw == WRITE)
 +              if (iov_iter_rw(iter) == WRITE)
                        truncate_inode_pages_range(mapping, lstart, end);
        }
  
 -      rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
 -                                iter, offset,
 -                                gfs2_get_block_direct, NULL, NULL, 0);
 +      rv = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter,
 +                                offset, gfs2_get_block_direct, NULL, NULL, 0);
  out:
        gfs2_glock_dq(&gh);
        gfs2_holder_uninit(&gh);
diff --combined fs/gfs2/file.c
@@@ -180,7 -180,7 +180,7 @@@ void gfs2_set_inode_flags(struct inode 
  
        flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_NOSEC);
        if ((ip->i_eattr == 0) && !is_sxid(inode->i_mode))
-               inode->i_flags |= S_NOSEC;
+               flags |= S_NOSEC;
        if (ip->i_diskflags & GFS2_DIF_IMMUTABLE)
                flags |= S_IMMUTABLE;
        if (ip->i_diskflags & GFS2_DIF_APPENDONLY)
@@@ -709,7 -709,7 +709,7 @@@ static ssize_t gfs2_file_write_iter(str
  
        gfs2_size_hint(file, iocb->ki_pos, iov_iter_count(from));
  
 -      if (file->f_flags & O_APPEND) {
 +      if (iocb->ki_flags & IOCB_APPEND) {
                struct gfs2_holder gh;
  
                ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
@@@ -917,7 -917,7 +917,7 @@@ static long gfs2_fallocate(struct file 
        struct gfs2_holder gh;
        int ret;
  
-       if (mode & ~FALLOC_FL_KEEP_SIZE)
+       if ((mode & ~FALLOC_FL_KEEP_SIZE) || gfs2_is_jdata(ip))
                return -EOPNOTSUPP;
  
        mutex_lock(&inode->i_mutex);
@@@ -1105,7 -1105,9 +1105,7 @@@ static int gfs2_flock(struct file *file
  
  const struct file_operations gfs2_file_fops = {
        .llseek         = gfs2_llseek,
 -      .read           = new_sync_read,
        .read_iter      = generic_file_read_iter,
 -      .write          = new_sync_write,
        .write_iter     = gfs2_file_write_iter,
        .unlocked_ioctl = gfs2_ioctl,
        .mmap           = gfs2_mmap,
@@@ -1135,7 -1137,9 +1135,7 @@@ const struct file_operations gfs2_dir_f
  
  const struct file_operations gfs2_file_fops_nolock = {
        .llseek         = gfs2_llseek,
 -      .read           = new_sync_read,
        .read_iter      = generic_file_read_iter,
 -      .write          = new_sync_write,
        .write_iter     = gfs2_file_write_iter,
        .unlocked_ioctl = gfs2_ioctl,
        .mmap           = gfs2_mmap,
diff --combined fs/gfs2/inode.c
@@@ -295,7 -295,7 +295,7 @@@ struct inode *gfs2_lookupi(struct inod
  
        if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) ||
            (name->len == 2 && memcmp(name->name, "..", 2) == 0 &&
 -           dir == sb->s_root->d_inode)) {
 +           dir == d_inode(sb->s_root))) {
                igrab(dir);
                return dir;
        }
@@@ -687,7 -687,7 +687,7 @@@ static int gfs2_create_inode(struct ino
        }
        gfs2_set_inode_flags(inode);
  
 -      if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) ||
 +      if ((GFS2_I(d_inode(sdp->sd_root_dir)) == dip) ||
            (dip->i_diskflags & GFS2_DIF_TOPDIR))
                aflags |= GFS2_AF_ORLOV;
  
@@@ -888,7 -888,7 +888,7 @@@ static int gfs2_link(struct dentry *old
  {
        struct gfs2_inode *dip = GFS2_I(dir);
        struct gfs2_sbd *sdp = GFS2_SB(dir);
 -      struct inode *inode = old_dentry->d_inode;
 +      struct inode *inode = d_inode(old_dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder ghs[2];
        struct buffer_head *dibh;
@@@ -1055,7 -1055,7 +1055,7 @@@ static int gfs2_unlink_ok(struct gfs2_i
  static int gfs2_unlink_inode(struct gfs2_inode *dip,
                             const struct dentry *dentry)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        int error;
  
@@@ -1091,7 -1091,7 +1091,7 @@@ static int gfs2_unlink(struct inode *di
  {
        struct gfs2_inode *dip = GFS2_I(dir);
        struct gfs2_sbd *sdp = GFS2_SB(dir);
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder ghs[3];
        struct gfs2_rgrpd *rgd;
@@@ -1227,8 -1227,8 +1227,8 @@@ static int gfs2_mknod(struct inode *dir
   */
  
  static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
-                             struct file *file, unsigned flags,
-                             umode_t mode, int *opened)
+                           struct file *file, unsigned flags,
+                           umode_t mode, int *opened)
  {
        struct dentry *d;
        bool excl = !!(flags & O_EXCL);
                return PTR_ERR(d);
        if (d != NULL)
                dentry = d;
 -      if (dentry->d_inode) {
 +      if (d_really_is_positive(dentry)) {
                if (!(*opened & FILE_OPENED))
                        return finish_no_open(file, d);
                dput(d);
@@@ -1282,7 -1282,7 +1282,7 @@@ static int gfs2_ok_to_move(struct gfs2_
                        error = -EINVAL;
                        break;
                }
 -              if (dir == sb->s_root->d_inode) {
 +              if (dir == d_inode(sb->s_root)) {
                        error = 0;
                        break;
                }
  }
  
  /**
+  * update_moved_ino - Update an inode that's being moved
+  * @ip: The inode being moved
+  * @ndip: The parent directory of the new filename
+  * @dir_rename: True of ip is a directory
+  *
+  * Returns: errno
+  */
+ 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;
+       gfs2_trans_add_meta(ip->i_gl, dibh);
+       gfs2_dinode_out(ip, dibh->b_data);
+       brelse(dibh);
+       return 0;
+ }
+ /**
   * gfs2_rename - Rename a file
   * @odir: Parent directory of old file name
   * @odentry: The old dentry of the file
@@@ -1321,7 -1350,7 +1350,7 @@@ static int gfs2_rename(struct inode *od
  {
        struct gfs2_inode *odip = GFS2_I(odir);
        struct gfs2_inode *ndip = GFS2_I(ndir);
 -      struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
 +      struct gfs2_inode *ip = GFS2_I(d_inode(odentry));
        struct gfs2_inode *nip = NULL;
        struct gfs2_sbd *sdp = GFS2_SB(odir);
        struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
        unsigned int x;
        int error;
  
 -      if (ndentry->d_inode) {
 -              nip = GFS2_I(ndentry->d_inode);
 +      if (d_really_is_positive(ndentry)) {
 +              nip = GFS2_I(d_inode(ndentry));
                if (ip == nip)
                        return 0;
        }
  
                if (S_ISDIR(ip->i_inode.i_mode)) {
                        dir_rename = 1;
-                       /* don't move a dirctory into it's subdir */
+                       /* don't move a directory into its subdir */
                        error = gfs2_ok_to_move(ip, ndip);
                        if (error)
                                goto out_gunlock_r;
        /* Check out the dir to be renamed */
  
        if (dir_rename) {
 -              error = gfs2_permission(odentry->d_inode, MAY_WRITE);
 +              error = gfs2_permission(d_inode(odentry), MAY_WRITE);
                if (error)
                        goto out_gunlock;
        }
        if (nip)
                error = gfs2_unlink_inode(ndip, ndentry);
  
-       if (dir_rename) {
-               error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);
-               if (error)
-                       goto out_end_trans;
-       } else {
-               struct buffer_head *dibh;
-               error = gfs2_meta_inode_buffer(ip, &dibh);
-               if (error)
-                       goto out_end_trans;
-               ip->i_inode.i_ctime = CURRENT_TIME;
-               gfs2_trans_add_meta(ip->i_gl, dibh);
-               gfs2_dinode_out(ip, dibh->b_data);
-               brelse(dibh);
-       }
+       error = update_moved_ino(ip, ndip, dir_rename);
+       if (error)
+               goto out_end_trans;
  
        error = gfs2_dir_del(odip, odentry);
        if (error)
  }
  
  /**
+  * gfs2_exchange - exchange two files
+  * @odir: Parent directory of old file name
+  * @odentry: The old dentry of the file
+  * @ndir: Parent directory of new file name
+  * @ndentry: The new dentry of the file
+  * @flags: The rename flags
+  *
+  * Returns: errno
+  */
+ static int gfs2_exchange(struct inode *odir, struct dentry *odentry,
+                        struct inode *ndir, struct dentry *ndentry,
+                        unsigned int flags)
+ {
+       struct gfs2_inode *odip = GFS2_I(odir);
+       struct gfs2_inode *ndip = GFS2_I(ndir);
+       struct gfs2_inode *oip = GFS2_I(odentry->d_inode);
+       struct gfs2_inode *nip = GFS2_I(ndentry->d_inode);
+       struct gfs2_sbd *sdp = GFS2_SB(odir);
+       struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
+       unsigned int num_gh;
+       unsigned int x;
+       umode_t old_mode = oip->i_inode.i_mode;
+       umode_t new_mode = nip->i_inode.i_mode;
+       int error;
+       error = gfs2_rindex_update(sdp);
+       if (error)
+               return error;
+       if (odip != ndip) {
+               error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
+                                          0, &r_gh);
+               if (error)
+                       goto out;
+               if (S_ISDIR(old_mode)) {
+                       /* don't move a directory into its subdir */
+                       error = gfs2_ok_to_move(oip, ndip);
+                       if (error)
+                               goto out_gunlock_r;
+               }
+               if (S_ISDIR(new_mode)) {
+                       /* don't move a directory into its subdir */
+                       error = gfs2_ok_to_move(nip, odip);
+                       if (error)
+                               goto out_gunlock_r;
+               }
+       }
+       num_gh = 1;
+       gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+       if (odip != ndip) {
+               gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+               num_gh++;
+       }
+       gfs2_holder_init(oip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+       num_gh++;
+       gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+       num_gh++;
+       for (x = 0; x < num_gh; x++) {
+               error = gfs2_glock_nq(ghs + x);
+               if (error)
+                       goto out_gunlock;
+       }
+       error = -ENOENT;
+       if (oip->i_inode.i_nlink == 0 || nip->i_inode.i_nlink == 0)
+               goto out_gunlock;
+       error = gfs2_unlink_ok(odip, &odentry->d_name, oip);
+       if (error)
+               goto out_gunlock;
+       error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);
+       if (error)
+               goto out_gunlock;
+       if (S_ISDIR(old_mode)) {
+               error = gfs2_permission(odentry->d_inode, MAY_WRITE);
+               if (error)
+                       goto out_gunlock;
+       }
+       if (S_ISDIR(new_mode)) {
+               error = gfs2_permission(ndentry->d_inode, MAY_WRITE);
+               if (error)
+                       goto out_gunlock;
+       }
+       error = gfs2_trans_begin(sdp, 4 * RES_DINODE + 4 * RES_LEAF, 0);
+       if (error)
+               goto out_gunlock;
+       error = update_moved_ino(oip, ndip, S_ISDIR(old_mode));
+       if (error)
+               goto out_end_trans;
+       error = update_moved_ino(nip, odip, S_ISDIR(new_mode));
+       if (error)
+               goto out_end_trans;
+       error = gfs2_dir_mvino(ndip, &ndentry->d_name, oip,
+                              IF2DT(old_mode));
+       if (error)
+               goto out_end_trans;
+       error = gfs2_dir_mvino(odip, &odentry->d_name, nip,
+                              IF2DT(new_mode));
+       if (error)
+               goto out_end_trans;
+       if (odip != ndip) {
+               if (S_ISDIR(new_mode) && !S_ISDIR(old_mode)) {
+                       inc_nlink(&odip->i_inode);
+                       drop_nlink(&ndip->i_inode);
+               } else if (S_ISDIR(old_mode) && !S_ISDIR(new_mode)) {
+                       inc_nlink(&ndip->i_inode);
+                       drop_nlink(&odip->i_inode);
+               }
+       }
+       mark_inode_dirty(&ndip->i_inode);
+       if (odip != ndip)
+               mark_inode_dirty(&odip->i_inode);
+ out_end_trans:
+       gfs2_trans_end(sdp);
+ out_gunlock:
+       while (x--) {
+               gfs2_glock_dq(ghs + x);
+               gfs2_holder_uninit(ghs + x);
+       }
+ out_gunlock_r:
+       if (r_gh.gh_gl)
+               gfs2_glock_dq_uninit(&r_gh);
+ out:
+       return error;
+ }
+ static int gfs2_rename2(struct inode *odir, struct dentry *odentry,
+                       struct inode *ndir, struct dentry *ndentry,
+                       unsigned int flags)
+ {
+       flags &= ~RENAME_NOREPLACE;
+       if (flags & ~RENAME_EXCHANGE)
+               return -EINVAL;
+       if (flags & RENAME_EXCHANGE)
+               return gfs2_exchange(odir, odentry, ndir, ndentry, flags);
+       return gfs2_rename(odir, odentry, ndir, ndentry);
+ }
+ /**
   * gfs2_follow_link - Follow a symbolic link
   * @dentry: The dentry of the link
   * @nd: Data that we pass to vfs_follow_link()
   * Returns: 0 on success or error code
   */
  
 -static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 +static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
  {
 -      struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
 +      struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
        struct gfs2_holder i_gh;
        struct buffer_head *dibh;
        unsigned int size;
        error = gfs2_glock_nq(&i_gh);
        if (error) {
                gfs2_holder_uninit(&i_gh);
 -              nd_set_link(nd, ERR_PTR(error));
 -              return NULL;
 +              return ERR_PTR(error);
        }
  
        size = (unsigned int)i_size_read(&ip->i_inode);
        brelse(dibh);
  out:
        gfs2_glock_dq_uninit(&i_gh);
 -      nd_set_link(nd, buf);
 -      return NULL;
 +      if (!IS_ERR(buf))
 +              *cookie = buf;
 +      return buf;
  }
  
  /**
@@@ -1716,7 -1889,7 +1889,7 @@@ static int setattr_chown(struct inode *
  
        if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
            !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {
-               gfs2_quota_change(ip, -ap.target, ouid, ogid);
+               gfs2_quota_change(ip, -(s64)ap.target, ouid, ogid);
                gfs2_quota_change(ip, ap.target, nuid, ngid);
        }
  
@@@ -1742,7 -1915,7 +1915,7 @@@ out
  
  static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder i_gh;
        int error;
@@@ -1798,7 -1971,7 +1971,7 @@@ out
  static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
                        struct kstat *stat)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int error;
  static int gfs2_setxattr(struct dentry *dentry, const char *name,
                         const void *data, size_t size, int flags)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int ret;
  static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
                             void *data, size_t size)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int ret;
  
  static int gfs2_removexattr(struct dentry *dentry, const char *name)
  {
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = d_inode(dentry);
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int ret;
@@@ -1943,7 -2116,7 +2116,7 @@@ const struct inode_operations gfs2_dir_
        .mkdir = gfs2_mkdir,
        .rmdir = gfs2_unlink,
        .mknod = gfs2_mknod,
-       .rename = gfs2_rename,
+       .rename2 = gfs2_rename2,
        .permission = gfs2_permission,
        .setattr = gfs2_setattr,
        .getattr = gfs2_getattr,
diff --combined fs/gfs2/ops_fstype.c
@@@ -647,7 -647,7 +647,7 @@@ out_unlock
  
  static int init_journal(struct gfs2_sbd *sdp, int undo)
  {
 -      struct inode *master = sdp->sd_master_dir->d_inode;
 +      struct inode *master = d_inode(sdp->sd_master_dir);
        struct gfs2_holder ji_gh;
        struct gfs2_inode *ip;
        int jindex = 1;
                }
        }
  
+       sdp->sd_log_idle = 1;
        set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
        gfs2_glock_dq_uninit(&ji_gh);
        jindex = 0;
@@@ -782,7 -783,7 +783,7 @@@ static struct lock_class_key gfs2_quota
  static int init_inodes(struct gfs2_sbd *sdp, int undo)
  {
        int error = 0;
 -      struct inode *master = sdp->sd_master_dir->d_inode;
 +      struct inode *master = d_inode(sdp->sd_master_dir);
  
        if (undo)
                goto fail_qinode;
@@@ -848,7 -849,7 +849,7 @@@ static int init_per_node(struct gfs2_sb
        char buf[30];
        int error = 0;
        struct gfs2_inode *ip;
 -      struct inode *master = sdp->sd_master_dir->d_inode;
 +      struct inode *master = d_inode(sdp->sd_master_dir);
  
        if (sdp->sd_args.ar_spectator)
                return 0;
@@@ -1357,7 -1358,7 +1358,7 @@@ static struct dentry *gfs2_mount_meta(s
                return ERR_PTR(error);
        }
        s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags,
 -               path.dentry->d_inode->i_sb->s_bdev);
 +               d_inode(path.dentry)->i_sb->s_bdev);
        path_put(&path);
        if (IS_ERR(s)) {
                pr_warn("gfs2 mount does not exist\n");
diff --combined fs/gfs2/quota.c
@@@ -649,9 -649,117 +649,117 @@@ static void do_qc(struct gfs2_quota_dat
                slot_hold(qd);
        }
  
+       if (change < 0) /* Reset quiet flag if we freed some blocks */
+               clear_bit(QDF_QMSG_QUIET, &qd->qd_flags);
        mutex_unlock(&sdp->sd_quota_mutex);
  }
  
+ static int gfs2_write_buf_to_page(struct gfs2_inode *ip, unsigned long index,
+                                 unsigned off, void *buf, unsigned bytes)
+ {
+       struct inode *inode = &ip->i_inode;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct address_space *mapping = inode->i_mapping;
+       struct page *page;
+       struct buffer_head *bh;
+       void *kaddr;
+       u64 blk;
+       unsigned bsize = sdp->sd_sb.sb_bsize, bnum = 0, boff = 0;
+       unsigned to_write = bytes, pg_off = off;
+       int done = 0;
+       blk = index << (PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift);
+       boff = off % bsize;
+       page = find_or_create_page(mapping, index, GFP_NOFS);
+       if (!page)
+               return -ENOMEM;
+       if (!page_has_buffers(page))
+               create_empty_buffers(page, bsize, 0);
+       bh = page_buffers(page);
+       while (!done) {
+               /* Find the beginning block within the page */
+               if (pg_off >= ((bnum * bsize) + bsize)) {
+                       bh = bh->b_this_page;
+                       bnum++;
+                       blk++;
+                       continue;
+               }
+               if (!buffer_mapped(bh)) {
+                       gfs2_block_map(inode, blk, bh, 1);
+                       if (!buffer_mapped(bh))
+                               goto unlock_out;
+                       /* If it's a newly allocated disk block, zero it */
+                       if (buffer_new(bh))
+                               zero_user(page, bnum * bsize, bh->b_size);
+               }
+               if (PageUptodate(page))
+                       set_buffer_uptodate(bh);
+               if (!buffer_uptodate(bh)) {
+                       ll_rw_block(READ | REQ_META, 1, &bh);
+                       wait_on_buffer(bh);
+                       if (!buffer_uptodate(bh))
+                               goto unlock_out;
+               }
+               gfs2_trans_add_data(ip->i_gl, bh);
+               /* If we need to write to the next block as well */
+               if (to_write > (bsize - boff)) {
+                       pg_off += (bsize - boff);
+                       to_write -= (bsize - boff);
+                       boff = pg_off % bsize;
+                       continue;
+               }
+               done = 1;
+       }
+       /* Write to the page, now that we have setup the buffer(s) */
+       kaddr = kmap_atomic(page);
+       memcpy(kaddr + off, buf, bytes);
+       flush_dcache_page(page);
+       kunmap_atomic(kaddr);
+       unlock_page(page);
+       page_cache_release(page);
+       return 0;
+ unlock_out:
+       unlock_page(page);
+       page_cache_release(page);
+       return -EIO;
+ }
+ static int gfs2_write_disk_quota(struct gfs2_inode *ip, struct gfs2_quota *qp,
+                                loff_t loc)
+ {
+       unsigned long pg_beg;
+       unsigned pg_off, nbytes, overflow = 0;
+       int pg_oflow = 0, error;
+       void *ptr;
+       nbytes = sizeof(struct gfs2_quota);
+       pg_beg = loc >> PAGE_CACHE_SHIFT;
+       pg_off = loc % PAGE_CACHE_SIZE;
+       /* If the quota straddles a page boundary, split the write in two */
+       if ((pg_off + nbytes) > PAGE_CACHE_SIZE) {
+               pg_oflow = 1;
+               overflow = (pg_off + nbytes) - PAGE_CACHE_SIZE;
+       }
+       ptr = qp;
+       error = gfs2_write_buf_to_page(ip, pg_beg, pg_off, ptr,
+                                      nbytes - overflow);
+       /* If there's an overflow, write the remaining bytes to the next page */
+       if (!error && pg_oflow)
+               error = gfs2_write_buf_to_page(ip, pg_beg + 1, 0,
+                                              ptr + nbytes - overflow,
+                                              overflow);
+       return error;
+ }
  /**
   * gfs2_adjust_quota - adjust record of current block usage
   * @ip: The quota inode
@@@ -672,15 -780,8 +780,8 @@@ static int gfs2_adjust_quota(struct gfs
  {
        struct inode *inode = &ip->i_inode;
        struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct address_space *mapping = inode->i_mapping;
-       unsigned long index = loc >> PAGE_CACHE_SHIFT;
-       unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
-       unsigned blocksize, iblock, pos;
-       struct buffer_head *bh;
-       struct page *page;
-       void *kaddr, *ptr;
        struct gfs2_quota q;
-       int err, nbytes;
+       int err;
        u64 size;
  
        if (gfs2_is_stuffed(ip)) {
        if (err < 0)
                return err;
  
+       loc -= sizeof(q); /* gfs2_internal_read would've advanced the loc ptr */
        err = -EIO;
        be64_add_cpu(&q.qu_value, change);
+       if (((s64)be64_to_cpu(q.qu_value)) < 0)
+               q.qu_value = 0; /* Never go negative on quota usage */
        qd->qd_qb.qb_value = q.qu_value;
        if (fdq) {
                if (fdq->d_fieldmask & QC_SPC_SOFT) {
                }
        }
  
-       /* Write the quota into the quota file on disk */
-       ptr = &q;
-       nbytes = sizeof(struct gfs2_quota);
- get_a_page:
-       page = find_or_create_page(mapping, index, GFP_NOFS);
-       if (!page)
-               return -ENOMEM;
-       blocksize = inode->i_sb->s_blocksize;
-       iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
-       if (!page_has_buffers(page))
-               create_empty_buffers(page, blocksize, 0);
-       bh = page_buffers(page);
-       pos = blocksize;
-       while (offset >= pos) {
-               bh = bh->b_this_page;
-               iblock++;
-               pos += blocksize;
-       }
-       if (!buffer_mapped(bh)) {
-               gfs2_block_map(inode, iblock, bh, 1);
-               if (!buffer_mapped(bh))
-                       goto unlock_out;
-               /* If it's a newly allocated disk block for quota, zero it */
-               if (buffer_new(bh))
-                       zero_user(page, pos - blocksize, bh->b_size);
-       }
-       if (PageUptodate(page))
-               set_buffer_uptodate(bh);
-       if (!buffer_uptodate(bh)) {
-               ll_rw_block(READ | REQ_META, 1, &bh);
-               wait_on_buffer(bh);
-               if (!buffer_uptodate(bh))
-                       goto unlock_out;
-       }
-       gfs2_trans_add_data(ip->i_gl, bh);
-       kaddr = kmap_atomic(page);
-       if (offset + sizeof(struct gfs2_quota) > PAGE_CACHE_SIZE)
-               nbytes = PAGE_CACHE_SIZE - offset;
-       memcpy(kaddr + offset, ptr, nbytes);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr);
-       unlock_page(page);
-       page_cache_release(page);
-       /* If quota straddles page boundary, we need to update the rest of the
-        * quota at the beginning of the next page */
-       if ((offset + sizeof(struct gfs2_quota)) > PAGE_CACHE_SIZE) {
-               ptr = ptr + nbytes;
-               nbytes = sizeof(struct gfs2_quota) - nbytes;
-               offset = 0;
-               index++;
-               goto get_a_page;
+       err = gfs2_write_disk_quota(ip, &q, loc);
+       if (!err) {
+               size = loc + sizeof(struct gfs2_quota);
+               if (size > inode->i_size)
+                       i_size_write(inode, size);
+               inode->i_mtime = inode->i_atime = CURRENT_TIME;
+               mark_inode_dirty(inode);
+               set_bit(QDF_REFRESH, &qd->qd_flags);
        }
  
-       size = loc + sizeof(struct gfs2_quota);
-       if (size > inode->i_size)
-               i_size_write(inode, size);
-       inode->i_mtime = inode->i_atime = CURRENT_TIME;
-       mark_inode_dirty(inode);
-       set_bit(QDF_REFRESH, &qd->qd_flags);
-       return 0;
- unlock_out:
-       unlock_page(page);
-       page_cache_release(page);
        return err;
  }
  
@@@ -1148,10 -1189,13 +1189,13 @@@ int gfs2_quota_check(struct gfs2_inode 
                        /* If no min_target specified or we don't meet
                         * min_target, return -EDQUOT */
                        if (!ap->min_target || ap->min_target > ap->allowed) {
-                               print_message(qd, "exceeded");
-                               quota_send_warning(qd->qd_id,
-                                                  sdp->sd_vfs->s_dev,
-                                                  QUOTA_NL_BHARDWARN);
+                               if (!test_and_set_bit(QDF_QMSG_QUIET,
+                                                     &qd->qd_flags)) {
+                                       print_message(qd, "exceeded");
+                                       quota_send_warning(qd->qd_id,
+                                                          sdp->sd_vfs->s_dev,
+                                                          QUOTA_NL_BHARDWARN);
+                               }
                                error = -EDQUOT;
                                break;
                        }
@@@ -1494,34 -1538,32 +1538,34 @@@ int gfs2_quotad(void *data
        return 0;
  }
  
 -static int gfs2_quota_get_xstate(struct super_block *sb,
 -                               struct fs_quota_stat *fqs)
 +static int gfs2_quota_get_state(struct super_block *sb, struct qc_state *state)
  {
        struct gfs2_sbd *sdp = sb->s_fs_info;
  
 -      memset(fqs, 0, sizeof(struct fs_quota_stat));
 -      fqs->qs_version = FS_QSTAT_VERSION;
 +      memset(state, 0, sizeof(*state));
  
        switch (sdp->sd_args.ar_quota) {
        case GFS2_QUOTA_ON:
 -              fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
 +              state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED;
 +              state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED;
                /*FALLTHRU*/
        case GFS2_QUOTA_ACCOUNT:
 -              fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT);
 +              state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED |
 +                                                QCI_SYSFILE;
 +              state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED |
 +                                                QCI_SYSFILE;
                break;
        case GFS2_QUOTA_OFF:
                break;
        }
 -
        if (sdp->sd_quota_inode) {
 -              fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr;
 -              fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks;
 +              state->s_state[USRQUOTA].ino =
 +                                      GFS2_I(sdp->sd_quota_inode)->i_no_addr;
 +              state->s_state[USRQUOTA].blocks = sdp->sd_quota_inode->i_blocks;
        }
 -      fqs->qs_uquota.qfs_nextents = 1; /* unsupported */
 -      fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */
 -      fqs->qs_incoredqs = list_lru_count(&gfs2_qd_lru);
 +      state->s_state[USRQUOTA].nextents = 1;  /* unsupported */
 +      state->s_state[GRPQUOTA] = state->s_state[USRQUOTA];
 +      state->s_incoredqs = list_lru_count(&gfs2_qd_lru);
        return 0;
  }
  
@@@ -1648,6 -1690,8 +1692,8 @@@ static int gfs2_set_dqblk(struct super_
  
        /* Apply changes */
        error = gfs2_adjust_quota(ip, offset, 0, qd, fdq);
+       if (!error)
+               clear_bit(QDF_QMSG_QUIET, &qd->qd_flags);
  
        gfs2_trans_end(sdp);
  out_release:
@@@ -1666,7 -1710,7 +1712,7 @@@ out_put
  
  const struct quotactl_ops gfs2_quotactl_ops = {
        .quota_sync     = gfs2_quota_sync,
 -      .get_xstate     = gfs2_quota_get_xstate,
 +      .get_state      = gfs2_quota_get_state,
        .get_dqblk      = gfs2_get_dqblk,
        .set_dqblk      = gfs2_set_dqblk,
  };