]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
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

fs/gfs2/aops.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/sys.c

index 5551fea0afd7c53803314f524d4ceef84b59eaf3..1caee05345878d38591a3d000466ecd3d147e937 100644 (file)
@@ -171,6 +171,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w
 /**
  * gfs2_jdata_writepage - Write complete page
  * @page: Page to write
+ * @wbc: The writeback control
  *
  * Returns: errno
  *
@@ -221,9 +222,10 @@ static int gfs2_writepages(struct address_space *mapping,
  * 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 @@ 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 @@ int gfs2_internal_read(struct gfs2_inode *ip, char *buf, loff_t *pos,
 
 /**
  * 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 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
  * @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)
  *
index 31892871ea87052ad423630f08b0e0d58589d686..cf4ab89159f48641017b0feb57971d6e5c6a38bd 100644 (file)
@@ -180,7 +180,7 @@ void gfs2_set_inode_flags(struct inode *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)
@@ -917,7 +917,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t le
        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);
index 0fa8062f85a7ab20332301ffafd1733940352096..a38e38f7b6fc37ae2e2b9ca5af0e59d7c5652856 100644 (file)
@@ -1076,7 +1076,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
                    !test_bit(GLF_DEMOTE, &gl->gl_flags))
                        fast_path = 1;
        }
-       if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl))
+       if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl) &&
+           (glops->go_flags & GLOF_LRU))
                gfs2_glock_add_to_lru(gl);
 
        trace_gfs2_glock_queue(gh, 0);
index fe91951c33617adbcae820f1cce048df84a254a8..fa3fa5e9455366b2ce0d2ebcb0438db7c8fdc58e 100644 (file)
@@ -144,6 +144,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
        struct gfs2_rgrpd *rgd;
        int error;
 
+       spin_lock(&gl->gl_spin);
+       rgd = gl->gl_object;
+       if (rgd)
+               gfs2_rgrp_brelse(rgd);
+       spin_unlock(&gl->gl_spin);
+
        if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
                return;
        GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
@@ -175,15 +181,17 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct address_space *mapping = &sdp->sd_aspace;
+       struct gfs2_rgrpd *rgd = gl->gl_object;
+
+       if (rgd)
+               gfs2_rgrp_brelse(rgd);
 
        WARN_ON_ONCE(!(flags & DIO_METADATA));
        gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
        truncate_inode_pages_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
 
-       if (gl->gl_object) {
-               struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object;
+       if (rgd)
                rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
-       }
 }
 
 /**
@@ -561,7 +569,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
        .go_lock = inode_go_lock,
        .go_dump = inode_go_dump,
        .go_type = LM_TYPE_INODE,
-       .go_flags = GLOF_ASPACE,
+       .go_flags = GLOF_ASPACE | GLOF_LRU,
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
@@ -584,10 +592,12 @@ const struct gfs2_glock_operations gfs2_freeze_glops = {
 const struct gfs2_glock_operations gfs2_iopen_glops = {
        .go_type = LM_TYPE_IOPEN,
        .go_callback = iopen_go_callback,
+       .go_flags = GLOF_LRU,
 };
 
 const struct gfs2_glock_operations gfs2_flock_glops = {
        .go_type = LM_TYPE_FLOCK,
+       .go_flags = GLOF_LRU,
 };
 
 const struct gfs2_glock_operations gfs2_nondisk_glops = {
@@ -596,7 +606,7 @@ const struct gfs2_glock_operations gfs2_nondisk_glops = {
 
 const struct gfs2_glock_operations gfs2_quota_glops = {
        .go_type = LM_TYPE_QUOTA,
-       .go_flags = GLOF_LVB,
+       .go_flags = GLOF_LVB | GLOF_LRU,
 };
 
 const struct gfs2_glock_operations gfs2_journal_glops = {
index 58b75abf6ab2f4e9e0c1b37752eba724a5b55b61..a1ec7c20e498220c75809e14bae2c2d63709b9a8 100644 (file)
@@ -225,6 +225,7 @@ struct gfs2_glock_operations {
        const unsigned long go_flags;
 #define GLOF_ASPACE 1
 #define GLOF_LVB    2
+#define GLOF_LRU    4
 };
 
 enum {
@@ -432,6 +433,7 @@ enum {
        QDF_CHANGE              = 1,
        QDF_LOCKED              = 2,
        QDF_REFRESH             = 3,
+       QDF_QMSG_QUIET          = 4,
 };
 
 struct gfs2_quota_data {
index 3a1461de1551d5765b7334747e69d2909ffb8d00..063fdfcf82758a0c77f4cc44fe7b1f873b3cbb21 100644 (file)
@@ -1227,8 +1227,8 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
  */
 
 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);
@@ -1306,6 +1306,35 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
        return error;
 }
 
+/**
+ * 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
@@ -1354,7 +1383,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
 
                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;
@@ -1494,20 +1523,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        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)
@@ -1538,6 +1556,161 @@ out:
        return 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
@@ -1716,7 +1889,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
 
        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);
        }
 
@@ -1943,7 +2116,7 @@ const struct inode_operations gfs2_dir_iops = {
        .mkdir = gfs2_mkdir,
        .rmdir = gfs2_unlink,
        .mknod = gfs2_mknod,
-       .rename = gfs2_rename,
+       .rename2 = gfs2_rename2,
        .permission = gfs2_permission,
        .setattr = gfs2_setattr,
        .getattr = gfs2_getattr,
index 35b49f44c72f03f03351d397cbabb6a027ee8c23..1e3a93f2f71d55d773f57d69e78ec56514295800 100644 (file)
@@ -756,6 +756,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                }
        }
 
+       sdp->sd_log_idle = 1;
        set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
        gfs2_glock_dq_uninit(&ji_gh);
        jindex = 0;
index e3065cb9ab087530cc53e59525f1854c6d191686..9b61f92fcfdf0c85f37210f3fe5e630715be0c8e 100644 (file)
@@ -649,9 +649,117 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
                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 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
 {
        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)) {
@@ -694,8 +795,11 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        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) {
@@ -712,79 +816,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
                }
        }
 
-       /* 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 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
                        /* 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;
                        }
@@ -1648,6 +1692,8 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
 
        /* 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:
index 6af2396a317c3de22e9d8bd86e28246b28067523..c6c62321dfd6f6918bd54cbd609347ed6d4c38d3 100644 (file)
@@ -978,10 +978,10 @@ static void set_rgrp_preferences(struct gfs2_sbd *sdp)
                rgd->rd_flags |= GFS2_RDF_PREFERRED;
                for (i = 0; i < sdp->sd_journals; i++) {
                        rgd = gfs2_rgrpd_get_next(rgd);
-                       if (rgd == first)
+                       if (!rgd || rgd == first)
                                break;
                }
-       } while (rgd != first);
+       } while (rgd && rgd != first);
 }
 
 /**
@@ -1244,14 +1244,13 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
 }
 
 /**
- * gfs2_rgrp_go_unlock - Release RG bitmaps read in with gfs2_rgrp_bh_get()
- * @gh: The glock holder for the resource group
+ * gfs2_rgrp_brelse - Release RG bitmaps read in with gfs2_rgrp_bh_get()
+ * @rgd: The resource group
  *
  */
 
-void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
+void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd)
 {
-       struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
        int x, length = rgd->rd_length;
 
        for (x = 0; x < length; x++) {
@@ -1264,6 +1263,22 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
 
 }
 
+/**
+ * gfs2_rgrp_go_unlock - Unlock a rgrp glock
+ * @gh: The glock holder for the resource group
+ *
+ */
+
+void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
+{
+       struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
+       int demote_requested = test_bit(GLF_DEMOTE, &gh->gh_gl->gl_flags) |
+               test_bit(GLF_PENDING_DEMOTE, &gh->gh_gl->gl_flags);
+
+       if (rgd && demote_requested)
+               gfs2_rgrp_brelse(rgd);
+}
+
 int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                             struct buffer_head *bh,
                             const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed)
@@ -1711,10 +1726,8 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
                return ret;
 
 bitmap_full:   /* Mark bitmap as full and fall through */
-               if ((state == GFS2_BLKST_FREE) && initial_offset == 0) {
-                       struct gfs2_bitmap *bi = rbm_bi(rbm);
+               if ((state == GFS2_BLKST_FREE) && initial_offset == 0)
                        set_bit(GBF_FULL, &bi->bi_flags);
-               }
 
 next_bitmap:   /* Find next bitmap in the rgrp */
                rbm->offset = 0;
@@ -1850,14 +1863,23 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops)
        const struct gfs2_sbd *sdp = gl->gl_sbd;
        struct gfs2_lkstats *st;
        s64 r_dcount, l_dcount;
-       s64 r_srttb, l_srttb;
+       s64 l_srttb, a_srttb = 0;
        s64 srttb_diff;
        s64 sqr_diff;
        s64 var;
+       int cpu, nonzero = 0;
 
        preempt_disable();
+       for_each_present_cpu(cpu) {
+               st = &per_cpu_ptr(sdp->sd_lkstats, cpu)->lkstats[LM_TYPE_RGRP];
+               if (st->stats[GFS2_LKS_SRTTB]) {
+                       a_srttb += st->stats[GFS2_LKS_SRTTB];
+                       nonzero++;
+               }
+       }
        st = &this_cpu_ptr(sdp->sd_lkstats)->lkstats[LM_TYPE_RGRP];
-       r_srttb = st->stats[GFS2_LKS_SRTTB];
+       if (nonzero)
+               do_div(a_srttb, nonzero);
        r_dcount = st->stats[GFS2_LKS_DCOUNT];
        var = st->stats[GFS2_LKS_SRTTVARB] +
              gl->gl_stats.stats[GFS2_LKS_SRTTVARB];
@@ -1866,10 +1888,10 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops)
        l_srttb = gl->gl_stats.stats[GFS2_LKS_SRTTB];
        l_dcount = gl->gl_stats.stats[GFS2_LKS_DCOUNT];
 
-       if ((l_dcount < 1) || (r_dcount < 1) || (r_srttb == 0))
+       if ((l_dcount < 1) || (r_dcount < 1) || (a_srttb == 0))
                return false;
 
-       srttb_diff = r_srttb - l_srttb;
+       srttb_diff = a_srttb - l_srttb;
        sqr_diff = srttb_diff * srttb_diff;
 
        var *= 2;
index 68972ecfbb019018f89f233da989a816117d2b01..c0ab33fa3eed1c2439da582a21eaf2eba9223455 100644 (file)
@@ -36,6 +36,7 @@ extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
 extern int gfs2_rindex_update(struct gfs2_sbd *sdp);
 extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
 extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh);
+extern void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd);
 extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
 
 extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
index ae8e8811f0e8ccc4ad367ebba6148d060ee961e3..c9ff1cf7d4f3ec9e4168d401ce595f9665c9e701 100644 (file)
@@ -101,8 +101,11 @@ static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
 
 static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 {
-       int error;
-       int n = simple_strtol(buf, NULL, 0);
+       int error, n;
+
+       error = kstrtoint(buf, 0, &n);
+       if (error)
+               return error;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -134,10 +137,16 @@ static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
 
 static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 {
+       int error, val;
+
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (simple_strtol(buf, NULL, 0) != 1)
+       error = kstrtoint(buf, 0, &val);
+       if (error)
+               return error;
+
+       if (val != 1)
                return -EINVAL;
 
        gfs2_lm_withdraw(sdp, "withdrawing from cluster at user's request\n");
@@ -148,10 +157,16 @@ static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
                                 size_t len)
 {
+       int error, val;
+
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (simple_strtol(buf, NULL, 0) != 1)
+       error = kstrtoint(buf, 0, &val);
+       if (error)
+               return error;
+
+       if (val != 1)
                return -EINVAL;
 
        gfs2_statfs_sync(sdp->sd_vfs, 0);
@@ -161,10 +176,16 @@ static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
 static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
                                size_t len)
 {
+       int error, val;
+
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (simple_strtol(buf, NULL, 0) != 1)
+       error = kstrtoint(buf, 0, &val);
+       if (error)
+               return error;
+
+       if (val != 1)
                return -EINVAL;
 
        gfs2_quota_sync(sdp->sd_vfs, 0);
@@ -181,7 +202,9 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       id = simple_strtoul(buf, NULL, 0);
+       error = kstrtou32(buf, 0, &id);
+       if (error)
+               return error;
 
        qid = make_kqid(current_user_ns(), USRQUOTA, id);
        if (!qid_valid(qid))
@@ -201,7 +224,9 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       id = simple_strtoul(buf, NULL, 0);
+       error = kstrtou32(buf, 0, &id);
+       if (error)
+               return error;
 
        qid = make_kqid(current_user_ns(), GRPQUOTA, id);
        if (!qid_valid(qid))
@@ -324,10 +349,11 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
 static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       ssize_t ret = len;
-       int val;
+       int ret, val;
 
-       val = simple_strtol(buf, NULL, 0);
+       ret = kstrtoint(buf, 0, &val);
+       if (ret)
+               return ret;
 
        if (val == 1)
                set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
@@ -336,9 +362,9 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
                smp_mb__after_atomic();
                gfs2_glock_thaw(sdp);
        } else {
-               ret = -EINVAL;
+               return -EINVAL;
        }
-       return ret;
+       return len;
 }
 
 static ssize_t wdack_show(struct gfs2_sbd *sdp, char *buf)
@@ -350,17 +376,18 @@ static ssize_t wdack_show(struct gfs2_sbd *sdp, char *buf)
 
 static ssize_t wdack_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 {
-       ssize_t ret = len;
-       int val;
+       int ret, val;
 
-       val = simple_strtol(buf, NULL, 0);
+       ret = kstrtoint(buf, 0, &val);
+       if (ret)
+               return ret;
 
        if ((val == 1) &&
            !strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm"))
                complete(&sdp->sd_wdack);
        else
-               ret = -EINVAL;
-       return ret;
+               return -EINVAL;
+       return len;
 }
 
 static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
@@ -553,11 +580,14 @@ static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,
 {
        struct gfs2_tune *gt = &sdp->sd_tune;
        unsigned int x;
+       int error;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       x = simple_strtoul(buf, NULL, 0);
+       error = kstrtouint(buf, 0, &x);
+       if (error)
+               return error;
 
        if (check_zero && !x)
                return -EINVAL;