Commit 546fac60 authored by Linus Torvalds's avatar Linus Torvalds

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
parents ebeaa8dd 39b0f1e9
...@@ -171,6 +171,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w ...@@ -171,6 +171,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w
/** /**
* gfs2_jdata_writepage - Write complete page * gfs2_jdata_writepage - Write complete page
* @page: Page to write * @page: Page to write
* @wbc: The writeback control
* *
* Returns: errno * Returns: errno
* *
...@@ -221,9 +222,10 @@ static int gfs2_writepages(struct address_space *mapping, ...@@ -221,9 +222,10 @@ static int gfs2_writepages(struct address_space *mapping,
* gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages * gfs2_write_jdata_pagevec - Write back a pagevec's worth of pages
* @mapping: The mapping * @mapping: The mapping
* @wbc: The writeback control * @wbc: The writeback control
* @writepage: The writepage function to call for each page
* @pvec: The vector of pages * @pvec: The vector of pages
* @nr_pages: The number of pages to write * @nr_pages: The number of pages to write
* @end: End position
* @done_index: Page index
* *
* Returns: non-zero if loop should terminate, zero otherwise * Returns: non-zero if loop should terminate, zero otherwise
*/ */
...@@ -333,8 +335,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, ...@@ -333,8 +335,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
* gfs2_write_cache_jdata - Like write_cache_pages but different * gfs2_write_cache_jdata - Like write_cache_pages but different
* @mapping: The mapping to write * @mapping: The mapping to write
* @wbc: The writeback control * @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 * The reason that we use our own function here is that we need to
* start transactions before we grab page locks. This allows us * 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, ...@@ -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 * 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: * Some notes:
* 1. This is only for readahead, so we can simply ignore any things * 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, ...@@ -853,7 +857,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
* @mapping: The address space to write to * @mapping: The address space to write to
* @pos: The file position * @pos: The file position
* @len: The length of the data * @len: The length of the data
* @copied: * @copied: How much was actually copied by the VFS
* @page: The page that has been written * @page: The page that has been written
* @fsdata: The fsdata (unused in GFS2) * @fsdata: The fsdata (unused in GFS2)
* *
......
...@@ -180,7 +180,7 @@ void gfs2_set_inode_flags(struct inode *inode) ...@@ -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); flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_NOSEC);
if ((ip->i_eattr == 0) && !is_sxid(inode->i_mode)) 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) if (ip->i_diskflags & GFS2_DIF_IMMUTABLE)
flags |= S_IMMUTABLE; flags |= S_IMMUTABLE;
if (ip->i_diskflags & GFS2_DIF_APPENDONLY) 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 ...@@ -917,7 +917,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t le
struct gfs2_holder gh; struct gfs2_holder gh;
int ret; int ret;
if (mode & ~FALLOC_FL_KEEP_SIZE) if ((mode & ~FALLOC_FL_KEEP_SIZE) || gfs2_is_jdata(ip))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
......
...@@ -1076,7 +1076,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh) ...@@ -1076,7 +1076,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
!test_bit(GLF_DEMOTE, &gl->gl_flags)) !test_bit(GLF_DEMOTE, &gl->gl_flags))
fast_path = 1; 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); gfs2_glock_add_to_lru(gl);
trace_gfs2_glock_queue(gh, 0); trace_gfs2_glock_queue(gh, 0);
......
...@@ -144,6 +144,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl) ...@@ -144,6 +144,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
int error; 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)) if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
return; return;
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); 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) ...@@ -175,15 +181,17 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
{ {
struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_sbd *sdp = gl->gl_sbd;
struct address_space *mapping = &sdp->sd_aspace; 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)); WARN_ON_ONCE(!(flags & DIO_METADATA));
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
truncate_inode_pages_range(mapping, gl->gl_vm.start, gl->gl_vm.end); truncate_inode_pages_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
if (gl->gl_object) { if (rgd)
struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object;
rgd->rd_flags &= ~GFS2_RDF_UPTODATE; rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
}
} }
/** /**
...@@ -561,7 +569,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { ...@@ -561,7 +569,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
.go_lock = inode_go_lock, .go_lock = inode_go_lock,
.go_dump = inode_go_dump, .go_dump = inode_go_dump,
.go_type = LM_TYPE_INODE, .go_type = LM_TYPE_INODE,
.go_flags = GLOF_ASPACE, .go_flags = GLOF_ASPACE | GLOF_LRU,
}; };
const struct gfs2_glock_operations gfs2_rgrp_glops = { const struct gfs2_glock_operations gfs2_rgrp_glops = {
...@@ -584,10 +592,12 @@ const struct gfs2_glock_operations gfs2_freeze_glops = { ...@@ -584,10 +592,12 @@ const struct gfs2_glock_operations gfs2_freeze_glops = {
const struct gfs2_glock_operations gfs2_iopen_glops = { const struct gfs2_glock_operations gfs2_iopen_glops = {
.go_type = LM_TYPE_IOPEN, .go_type = LM_TYPE_IOPEN,
.go_callback = iopen_go_callback, .go_callback = iopen_go_callback,
.go_flags = GLOF_LRU,
}; };
const struct gfs2_glock_operations gfs2_flock_glops = { const struct gfs2_glock_operations gfs2_flock_glops = {
.go_type = LM_TYPE_FLOCK, .go_type = LM_TYPE_FLOCK,
.go_flags = GLOF_LRU,
}; };
const struct gfs2_glock_operations gfs2_nondisk_glops = { const struct gfs2_glock_operations gfs2_nondisk_glops = {
...@@ -596,7 +606,7 @@ 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 = { const struct gfs2_glock_operations gfs2_quota_glops = {
.go_type = LM_TYPE_QUOTA, .go_type = LM_TYPE_QUOTA,
.go_flags = GLOF_LVB, .go_flags = GLOF_LVB | GLOF_LRU,
}; };
const struct gfs2_glock_operations gfs2_journal_glops = { const struct gfs2_glock_operations gfs2_journal_glops = {
......
...@@ -225,6 +225,7 @@ struct gfs2_glock_operations { ...@@ -225,6 +225,7 @@ struct gfs2_glock_operations {
const unsigned long go_flags; const unsigned long go_flags;
#define GLOF_ASPACE 1 #define GLOF_ASPACE 1
#define GLOF_LVB 2 #define GLOF_LVB 2
#define GLOF_LRU 4
}; };
enum { enum {
...@@ -432,6 +433,7 @@ enum { ...@@ -432,6 +433,7 @@ enum {
QDF_CHANGE = 1, QDF_CHANGE = 1,
QDF_LOCKED = 2, QDF_LOCKED = 2,
QDF_REFRESH = 3, QDF_REFRESH = 3,
QDF_QMSG_QUIET = 4,
}; };
struct gfs2_quota_data { struct gfs2_quota_data {
......
...@@ -1306,6 +1306,35 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) ...@@ -1306,6 +1306,35 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
return error; 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 * gfs2_rename - Rename a file
* @odir: Parent directory of old file name * @odir: Parent directory of old file name
...@@ -1354,7 +1383,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1354,7 +1383,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (S_ISDIR(ip->i_inode.i_mode)) { if (S_ISDIR(ip->i_inode.i_mode)) {
dir_rename = 1; 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); error = gfs2_ok_to_move(ip, ndip);
if (error) if (error)
goto out_gunlock_r; goto out_gunlock_r;
...@@ -1494,20 +1523,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1494,20 +1523,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (nip) if (nip)
error = gfs2_unlink_inode(ndip, ndentry); error = gfs2_unlink_inode(ndip, ndentry);
if (dir_rename) { error = update_moved_ino(ip, ndip, 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) if (error)
goto out_end_trans; 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 = gfs2_dir_del(odip, odentry); error = gfs2_dir_del(odip, odentry);
if (error) if (error)
...@@ -1538,6 +1556,161 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1538,6 +1556,161 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
return error; 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 * gfs2_follow_link - Follow a symbolic link
* @dentry: The dentry of the link * @dentry: The dentry of the link
...@@ -1716,7 +1889,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1716,7 +1889,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
!gid_eq(ogid, NO_GID_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); gfs2_quota_change(ip, ap.target, nuid, ngid);
} }
...@@ -1943,7 +2116,7 @@ const struct inode_operations gfs2_dir_iops = { ...@@ -1943,7 +2116,7 @@ const struct inode_operations gfs2_dir_iops = {
.mkdir = gfs2_mkdir, .mkdir = gfs2_mkdir,
.rmdir = gfs2_unlink, .rmdir = gfs2_unlink,
.mknod = gfs2_mknod, .mknod = gfs2_mknod,
.rename = gfs2_rename, .rename2 = gfs2_rename2,
.permission = gfs2_permission, .permission = gfs2_permission,
.setattr = gfs2_setattr, .setattr = gfs2_setattr,
.getattr = gfs2_getattr, .getattr = gfs2_getattr,
......
...@@ -756,6 +756,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -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); set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
gfs2_glock_dq_uninit(&ji_gh); gfs2_glock_dq_uninit(&ji_gh);
jindex = 0; jindex = 0;
......
...@@ -649,9 +649,117 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) ...@@ -649,9 +649,117 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
slot_hold(qd); 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); 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 * gfs2_adjust_quota - adjust record of current block usage
* @ip: The quota inode * @ip: The quota inode
...@@ -672,15 +780,8 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -672,15 +780,8 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
{ {
struct inode *inode = &ip->i_inode; struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(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; struct gfs2_quota q;
int err, nbytes; int err;
u64 size; u64 size;
if (gfs2_is_stuffed(ip)) { if (gfs2_is_stuffed(ip)) {
...@@ -694,8 +795,11 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -694,8 +795,11 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
if (err < 0) if (err < 0)
return err; return err;
loc -= sizeof(q); /* gfs2_internal_read would've advanced the loc ptr */
err = -EIO; err = -EIO;
be64_add_cpu(&q.qu_value, change); 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; qd->qd_qb.qb_value = q.qu_value;
if (fdq) { if (fdq) {
if (fdq->d_fieldmask & QC_SPC_SOFT) { if (fdq->d_fieldmask & QC_SPC_SOFT) {
...@@ -712,79 +816,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -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 */ err = gfs2_write_disk_quota(ip, &q, loc);
ptr = &q; if (!err) {
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;
}
size = loc + sizeof(struct gfs2_quota); size = loc + sizeof(struct gfs2_quota);
if (size > inode->i_size) if (size > inode->i_size)
i_size_write(inode, size); i_size_write(inode, size);
inode->i_mtime = inode->i_atime = CURRENT_TIME; inode->i_mtime = inode->i_atime = CURRENT_TIME;
mark_inode_dirty(inode); mark_inode_dirty(inode);
set_bit(QDF_REFRESH, &qd->qd_flags); set_bit(QDF_REFRESH, &qd->qd_flags);
return 0; }
unlock_out:
unlock_page(page);
page_cache_release(page);
return err; return err;
} }
...@@ -1148,10 +1189,13 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, ...@@ -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 /* If no min_target specified or we don't meet
* min_target, return -EDQUOT */ * min_target, return -EDQUOT */
if (!ap->min_target || ap->min_target > ap->allowed) { if (!ap->min_target || ap->min_target > ap->allowed) {
if (!test_and_set_bit(QDF_QMSG_QUIET,
&qd->qd_flags)) {
print_message(qd, "exceeded"); print_message(qd, "exceeded");
quota_send_warning(qd->qd_id, quota_send_warning(qd->qd_id,
sdp->sd_vfs->s_dev, sdp->sd_vfs->s_dev,
QUOTA_NL_BHARDWARN); QUOTA_NL_BHARDWARN);
}
error = -EDQUOT; error = -EDQUOT;
break; break;
} }
...@@ -1648,6 +1692,8 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid, ...@@ -1648,6 +1692,8 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
/* Apply changes */ /* Apply changes */
error = gfs2_adjust_quota(ip, offset, 0, qd, fdq); error = gfs2_adjust_quota(ip, offset, 0, qd, fdq);
if (!error)
clear_bit(QDF_QMSG_QUIET, &qd->qd_flags);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_release: out_release:
......
...@@ -978,10 +978,10 @@ static void set_rgrp_preferences(struct gfs2_sbd *sdp) ...@@ -978,10 +978,10 @@ static void set_rgrp_preferences(struct gfs2_sbd *sdp)
rgd->rd_flags |= GFS2_RDF_PREFERRED; rgd->rd_flags |= GFS2_RDF_PREFERRED;
for (i = 0; i < sdp->sd_journals; i++) { for (i = 0; i < sdp->sd_journals; i++) {
rgd = gfs2_rgrpd_get_next(rgd); rgd = gfs2_rgrpd_get_next(rgd);
if (rgd == first) if (!rgd || rgd == first)
break; break;
} }
} while (rgd != first); } while (rgd && rgd != first);
} }
/** /**
...@@ -1244,14 +1244,13 @@ int gfs2_rgrp_go_lock(struct gfs2_holder *gh) ...@@ -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() * gfs2_rgrp_brelse - Release RG bitmaps read in with gfs2_rgrp_bh_get()
* @gh: The glock holder for the resource group * @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; int x, length = rgd->rd_length;
for (x = 0; x < length; x++) { for (x = 0; x < length; x++) {
...@@ -1264,6 +1263,22 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh) ...@@ -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, int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
struct buffer_head *bh, struct buffer_head *bh,
const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed) 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, ...@@ -1711,10 +1726,8 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext,
return ret; return ret;
bitmap_full: /* Mark bitmap as full and fall through */ bitmap_full: /* Mark bitmap as full and fall through */
if ((state == GFS2_BLKST_FREE) && initial_offset == 0) { if ((state == GFS2_BLKST_FREE) && initial_offset == 0)
struct gfs2_bitmap *bi = rbm_bi(rbm);
set_bit(GBF_FULL, &bi->bi_flags); set_bit(GBF_FULL, &bi->bi_flags);
}
next_bitmap: /* Find next bitmap in the rgrp */ next_bitmap: /* Find next bitmap in the rgrp */
rbm->offset = 0; rbm->offset = 0;
...@@ -1850,14 +1863,23 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops) ...@@ -1850,14 +1863,23 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops)
const struct gfs2_sbd *sdp = gl->gl_sbd; const struct gfs2_sbd *sdp = gl->gl_sbd;
struct gfs2_lkstats *st; struct gfs2_lkstats *st;
s64 r_dcount, l_dcount; s64 r_dcount, l_dcount;
s64 r_srttb, l_srttb; s64 l_srttb, a_srttb = 0;
s64 srttb_diff; s64 srttb_diff;
s64 sqr_diff; s64 sqr_diff;
s64 var; s64 var;
int cpu, nonzero = 0;
preempt_disable(); 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]; 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]; r_dcount = st->stats[GFS2_LKS_DCOUNT];
var = st->stats[GFS2_LKS_SRTTVARB] + var = st->stats[GFS2_LKS_SRTTVARB] +
gl->gl_stats.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) ...@@ -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_srttb = gl->gl_stats.stats[GFS2_LKS_SRTTB];
l_dcount = gl->gl_stats.stats[GFS2_LKS_DCOUNT]; 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; return false;
srttb_diff = r_srttb - l_srttb; srttb_diff = a_srttb - l_srttb;
sqr_diff = srttb_diff * srttb_diff; sqr_diff = srttb_diff * srttb_diff;
var *= 2; var *= 2;
......
...@@ -36,6 +36,7 @@ extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp); ...@@ -36,6 +36,7 @@ extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
extern int gfs2_rindex_update(struct gfs2_sbd *sdp); extern int gfs2_rindex_update(struct gfs2_sbd *sdp);
extern void gfs2_free_clones(struct gfs2_rgrpd *rgd); extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh); 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 void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); 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) ...@@ -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) static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
{ {
int error; int error, n;
int n = simple_strtol(buf, NULL, 0);
error = kstrtoint(buf, 0, &n);
if (error)
return error;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
...@@ -134,10 +137,16 @@ static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf) ...@@ -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) static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
{ {
int error, val;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (simple_strtol(buf, NULL, 0) != 1) error = kstrtoint(buf, 0, &val);
if (error)
return error;
if (val != 1)
return -EINVAL; return -EINVAL;
gfs2_lm_withdraw(sdp, "withdrawing from cluster at user's request\n"); 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) ...@@ -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, static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
size_t len) size_t len)
{ {
int error, val;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (simple_strtol(buf, NULL, 0) != 1) error = kstrtoint(buf, 0, &val);
if (error)
return error;
if (val != 1)
return -EINVAL; return -EINVAL;
gfs2_statfs_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0);
...@@ -161,10 +176,16 @@ static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf, ...@@ -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, static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
size_t len) size_t len)
{ {
int error, val;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (simple_strtol(buf, NULL, 0) != 1) error = kstrtoint(buf, 0, &val);
if (error)
return error;
if (val != 1)
return -EINVAL; return -EINVAL;
gfs2_quota_sync(sdp->sd_vfs, 0); 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, ...@@ -181,7 +202,9 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; 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); qid = make_kqid(current_user_ns(), USRQUOTA, id);
if (!qid_valid(qid)) if (!qid_valid(qid))
...@@ -201,7 +224,9 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, ...@@ -201,7 +224,9 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; 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); qid = make_kqid(current_user_ns(), GRPQUOTA, id);
if (!qid_valid(qid)) if (!qid_valid(qid))
...@@ -324,10 +349,11 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf) ...@@ -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) static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
{ {
struct lm_lockstruct *ls = &sdp->sd_lockstruct; struct lm_lockstruct *ls = &sdp->sd_lockstruct;
ssize_t ret = len; int ret, val;
int val;
val = simple_strtol(buf, NULL, 0); ret = kstrtoint(buf, 0, &val);
if (ret)
return ret;
if (val == 1) if (val == 1)
set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); 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) ...@@ -336,9 +362,9 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
smp_mb__after_atomic(); smp_mb__after_atomic();
gfs2_glock_thaw(sdp); gfs2_glock_thaw(sdp);
} else { } else {
ret = -EINVAL; return -EINVAL;
} }
return ret; return len;
} }
static ssize_t wdack_show(struct gfs2_sbd *sdp, char *buf) 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) ...@@ -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) static ssize_t wdack_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
{ {
ssize_t ret = len; int ret, val;
int val;
val = simple_strtol(buf, NULL, 0); ret = kstrtoint(buf, 0, &val);
if (ret)
return ret;
if ((val == 1) && if ((val == 1) &&
!strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm")) !strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm"))
complete(&sdp->sd_wdack); complete(&sdp->sd_wdack);
else else
ret = -EINVAL; return -EINVAL;
return ret; return len;
} }
static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) 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, ...@@ -553,11 +580,14 @@ static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,
{ {
struct gfs2_tune *gt = &sdp->sd_tune; struct gfs2_tune *gt = &sdp->sd_tune;
unsigned int x; unsigned int x;
int error;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
x = simple_strtoul(buf, NULL, 0); error = kstrtouint(buf, 0, &x);
if (error)
return error;
if (check_zero && !x) if (check_zero && !x)
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment