Merge tag 'gfs2-merge-window' of git://git.kernel.org:/pub/scm/linux/kernel/git/gfs2/linux-gfs2
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
This commit is contained in:
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
211
fs/gfs2/inode.c
211
fs/gfs2/inode.c
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
212
fs/gfs2/quota.c
212
fs/gfs2/quota.c
@@ -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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user