提交 4d589677 编写于 作者: L 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 is a list of patches we've accumulated for GFS2 for the current
  upstream merge window.  Last window's set was short, but I warned that
  this one would be bigger, and so it is.  We've got 19 patches:

   - A patch from Abhi Das to propagate the GFS2_DIF_SYSTEM bit so that
     newly added journals don't get flagged, deleted, and recreated by
     fsck.gfs2.

   - Two patches from Andreas Gruenbacher to improve GFS2 performance
     where extended attributes are involved.

   - A patch from Andy Price to fix a suspicious rcu dereference error.

   - Two patches from Ben Marzinski that rework how GFS2's NFS cookies
     are managed.  This fixes readdir problems with nfs-over-gfs2.

   - A patch from Ben Marzinski that fixes a race in unmounting GFS2.

   - A set of four patches from me to move the resource group
     reservations inside the gfs2 inode to improve performance and fix a
     bug whereby get_write_access improperly prevented some operations
     like chown.

   - A patch from me to spinlock-protect the setting of system statfs
     file data.  This was causing small discrepancies between df and du.

   - A patch from me to reintroduce a timeout while clearing glocks
     which was accidentally dropped some time ago.

   - A patch from me to wait for iopen glock dequeues in order to
     improve deleting of files that were unlinked from a different
     cluster node.

   - A patch from me to ensure metadata address spaces get truncated
     when an inode is evicted.

   - A patch from me to fix a bug in which a memory leak could occur in
     some error cases when inodes were trying to be created.

   - A patch to consistently use iopen glocks to transition from the
     unlinked state to the deleted state.

   - A patch to fix a glock reference count error when inode creation
     fails.

   - A patch from Junxiao Bi to fix an flock panic.

   - A patch from Markus Elfring that removes an unnecessary if"

* tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: fix flock panic issue
  GFS2: Don't do glock put on when inode creation fails
  GFS2: Always use iopen glock for gl_deletes
  GFS2: Release iopen glock in gfs2_create_inode error cases
  GFS2: Truncate address space mapping when deleting an inode
  GFS2: Wait for iopen glock dequeues
  gfs2: clear journal live bit in	gfs2_log_flush
  gfs2: change gfs2 readdir cookie
  gfs2: keep offset when splitting dir leaf blocks
  GFS2: Reintroduce a timeout in function gfs2_gl_hash_clear
  GFS2: Update master statfs buffer with sd_statfs_spin locked
  GFS2: Reduce size of incore inode
  GFS2: Make rgrp reservations part of the gfs2_inode structure
  GFS2: Extract quota data from reservations structure (revert 5407e242)
  gfs2: Extended attribute readahead optimization
  gfs2: Extended attribute readahead
  GFS2: Use rht_for_each_entry_rcu in glock_hash_walk
  GFS2: Delete an unnecessary check before the function call "iput"
  gfs2: Automatically set GFS2_DIF_SYSTEM flag on system files
...@@ -914,7 +914,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, ...@@ -914,7 +914,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
failed: failed:
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_inplace_release(ip); gfs2_inplace_release(ip);
if (ip->i_res->rs_qa_qd_num) if (ip->i_qadata && ip->i_qadata->qa_qd_num)
gfs2_quota_unlock(ip); gfs2_quota_unlock(ip);
if (inode == sdp->sd_rindex) { if (inode == sdp->sd_rindex) {
gfs2_glock_dq(&m_ip->i_gh); gfs2_glock_dq(&m_ip->i_gh);
......
...@@ -787,8 +787,8 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -787,8 +787,8 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
if (error) if (error)
goto out_rlist; goto out_rlist;
if (gfs2_rs_active(ip->i_res)) /* needs to be done with the rgrp glock held */ if (gfs2_rs_active(&ip->i_res)) /* needs to be done with the rgrp glock held */
gfs2_rs_deltree(ip->i_res); gfs2_rs_deltree(&ip->i_res);
error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
RES_INDIRECT + RES_STATFS + RES_QUOTA, RES_INDIRECT + RES_STATFS + RES_QUOTA,
...@@ -1291,13 +1291,9 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) ...@@ -1291,13 +1291,9 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
if (ret) if (ret)
return ret; return ret;
ret = get_write_access(inode);
if (ret)
return ret;
inode_dio_wait(inode); inode_dio_wait(inode);
ret = gfs2_rs_alloc(ip); ret = gfs2_rsqa_alloc(ip);
if (ret) if (ret)
goto out; goto out;
...@@ -1307,10 +1303,9 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize) ...@@ -1307,10 +1303,9 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
goto out; goto out;
} }
gfs2_rs_deltree(ip->i_res);
ret = do_shrink(inode, oldsize, newsize); ret = do_shrink(inode, oldsize, newsize);
out: out:
put_write_access(inode); gfs2_rsqa_delete(ip, NULL);
return ret; return ret;
} }
......
...@@ -82,6 +82,8 @@ ...@@ -82,6 +82,8 @@
#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) #define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
#define GFS2_HASH_INDEX_MASK 0xffffc000
#define GFS2_USE_HASH_FLAG 0x2000
struct qstr gfs2_qdot __read_mostly; struct qstr gfs2_qdot __read_mostly;
struct qstr gfs2_qdotdot __read_mostly; struct qstr gfs2_qdotdot __read_mostly;
...@@ -108,7 +110,7 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, ...@@ -108,7 +110,7 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block,
struct buffer_head *bh; struct buffer_head *bh;
int error; int error;
error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh); error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, 0, &bh);
if (error) if (error)
return error; return error;
if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) {
...@@ -305,7 +307,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf, ...@@ -305,7 +307,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
BUG_ON(extlen < 1); BUG_ON(extlen < 1);
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
} else { } else {
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, 0, &bh);
if (error) if (error)
goto fail; goto fail;
} }
...@@ -443,6 +445,27 @@ static int gfs2_dirent_last(const struct gfs2_dirent *dent, ...@@ -443,6 +445,27 @@ static int gfs2_dirent_last(const struct gfs2_dirent *dent,
return 0; return 0;
} }
/* Look for the dirent that contains the offset specified in data. Once we
* find that dirent, there must be space available there for the new dirent */
static int gfs2_dirent_find_offset(const struct gfs2_dirent *dent,
const struct qstr *name,
void *ptr)
{
unsigned required = GFS2_DIRENT_SIZE(name->len);
unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
unsigned totlen = be16_to_cpu(dent->de_rec_len);
if (ptr < (void *)dent || ptr >= (void *)dent + totlen)
return 0;
if (gfs2_dirent_sentinel(dent))
actual = 0;
if (ptr < (void *)dent + actual)
return -1;
if ((void *)dent + totlen >= ptr + required)
return 1;
return -1;
}
static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, static int gfs2_dirent_find_space(const struct gfs2_dirent *dent,
const struct qstr *name, const struct qstr *name,
void *opaque) void *opaque)
...@@ -682,6 +705,27 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, ...@@ -682,6 +705,27 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh,
prev->de_rec_len = cpu_to_be16(prev_rec_len); prev->de_rec_len = cpu_to_be16(prev_rec_len);
} }
static struct gfs2_dirent *do_init_dirent(struct inode *inode,
struct gfs2_dirent *dent,
const struct qstr *name,
struct buffer_head *bh,
unsigned offset)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_dirent *ndent;
unsigned totlen;
totlen = be16_to_cpu(dent->de_rec_len);
BUG_ON(offset + name->len > totlen);
gfs2_trans_add_meta(ip->i_gl, bh);
ndent = (struct gfs2_dirent *)((char *)dent + offset);
dent->de_rec_len = cpu_to_be16(offset);
gfs2_qstr2dirent(name, totlen - offset, ndent);
return ndent;
}
/* /*
* Takes a dent from which to grab space as an argument. Returns the * Takes a dent from which to grab space as an argument. Returns the
* newly created dent. * newly created dent.
...@@ -691,31 +735,25 @@ static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, ...@@ -691,31 +735,25 @@ static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode,
const struct qstr *name, const struct qstr *name,
struct buffer_head *bh) struct buffer_head *bh)
{ {
struct gfs2_inode *ip = GFS2_I(inode); unsigned offset = 0;
struct gfs2_dirent *ndent;
unsigned offset = 0, totlen;
if (!gfs2_dirent_sentinel(dent)) if (!gfs2_dirent_sentinel(dent))
offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
totlen = be16_to_cpu(dent->de_rec_len); return do_init_dirent(inode, dent, name, bh, offset);
BUG_ON(offset + name->len > totlen);
gfs2_trans_add_meta(ip->i_gl, bh);
ndent = (struct gfs2_dirent *)((char *)dent + offset);
dent->de_rec_len = cpu_to_be16(offset);
gfs2_qstr2dirent(name, totlen - offset, ndent);
return ndent;
} }
static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, static struct gfs2_dirent *gfs2_dirent_split_alloc(struct inode *inode,
struct buffer_head *bh, struct buffer_head *bh,
const struct qstr *name) const struct qstr *name,
void *ptr)
{ {
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
gfs2_dirent_find_space, name, NULL); gfs2_dirent_find_offset, name, ptr);
if (!dent || IS_ERR(dent)) if (!dent || IS_ERR(dent))
return dent; return dent;
return gfs2_init_dirent(inode, dent, name, bh); return do_init_dirent(inode, dent, name, bh,
(unsigned)(ptr - (void *)dent));
} }
static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,
...@@ -723,7 +761,7 @@ static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, ...@@ -723,7 +761,7 @@ static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,
{ {
int error; int error;
error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, 0, bhp);
if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) { if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {
/* pr_info("block num=%llu\n", leaf_no); */ /* pr_info("block num=%llu\n", leaf_no); */
error = -EIO; error = -EIO;
...@@ -1051,10 +1089,11 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -1051,10 +1089,11 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
if (!gfs2_dirent_sentinel(dent) && if (!gfs2_dirent_sentinel(dent) &&
be32_to_cpu(dent->de_hash) < divider) { be32_to_cpu(dent->de_hash) < divider) {
struct qstr str; struct qstr str;
void *ptr = ((char *)dent - obh->b_data) + nbh->b_data;
str.name = (char*)(dent+1); str.name = (char*)(dent+1);
str.len = be16_to_cpu(dent->de_name_len); str.len = be16_to_cpu(dent->de_name_len);
str.hash = be32_to_cpu(dent->de_hash); str.hash = be32_to_cpu(dent->de_hash);
new = gfs2_dirent_alloc(inode, nbh, &str); new = gfs2_dirent_split_alloc(inode, nbh, &str, ptr);
if (IS_ERR(new)) { if (IS_ERR(new)) {
error = PTR_ERR(new); error = PTR_ERR(new);
break; break;
...@@ -1186,10 +1225,10 @@ static int compare_dents(const void *a, const void *b) ...@@ -1186,10 +1225,10 @@ static int compare_dents(const void *a, const void *b)
int ret = 0; int ret = 0;
dent_a = *(const struct gfs2_dirent **)a; dent_a = *(const struct gfs2_dirent **)a;
hash_a = be32_to_cpu(dent_a->de_hash); hash_a = dent_a->de_cookie;
dent_b = *(const struct gfs2_dirent **)b; dent_b = *(const struct gfs2_dirent **)b;
hash_b = be32_to_cpu(dent_b->de_hash); hash_b = dent_b->de_cookie;
if (hash_a > hash_b) if (hash_a > hash_b)
ret = 1; ret = 1;
...@@ -1227,19 +1266,20 @@ static int compare_dents(const void *a, const void *b) ...@@ -1227,19 +1266,20 @@ static int compare_dents(const void *a, const void *b)
*/ */
static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx, static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx,
const struct gfs2_dirent **darr, u32 entries, struct gfs2_dirent **darr, u32 entries,
int *copied) u32 sort_start, int *copied)
{ {
const struct gfs2_dirent *dent, *dent_next; const struct gfs2_dirent *dent, *dent_next;
u64 off, off_next; u64 off, off_next;
unsigned int x, y; unsigned int x, y;
int run = 0; int run = 0;
sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL); if (sort_start < entries)
sort(&darr[sort_start], entries - sort_start,
sizeof(struct gfs2_dirent *), compare_dents, NULL);
dent_next = darr[0]; dent_next = darr[0];
off_next = be32_to_cpu(dent_next->de_hash); off_next = dent_next->de_cookie;
off_next = gfs2_disk_hash2offset(off_next);
for (x = 0, y = 1; x < entries; x++, y++) { for (x = 0, y = 1; x < entries; x++, y++) {
dent = dent_next; dent = dent_next;
...@@ -1247,8 +1287,7 @@ static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx, ...@@ -1247,8 +1287,7 @@ static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx,
if (y < entries) { if (y < entries) {
dent_next = darr[y]; dent_next = darr[y];
off_next = be32_to_cpu(dent_next->de_hash); off_next = dent_next->de_cookie;
off_next = gfs2_disk_hash2offset(off_next);
if (off < ctx->pos) if (off < ctx->pos)
continue; continue;
...@@ -1295,6 +1334,40 @@ static void *gfs2_alloc_sort_buffer(unsigned size) ...@@ -1295,6 +1334,40 @@ static void *gfs2_alloc_sort_buffer(unsigned size)
return ptr; return ptr;
} }
static int gfs2_set_cookies(struct gfs2_sbd *sdp, struct buffer_head *bh,
unsigned leaf_nr, struct gfs2_dirent **darr,
unsigned entries)
{
int sort_id = -1;
int i;
for (i = 0; i < entries; i++) {
unsigned offset;
darr[i]->de_cookie = be32_to_cpu(darr[i]->de_hash);
darr[i]->de_cookie = gfs2_disk_hash2offset(darr[i]->de_cookie);
if (!sdp->sd_args.ar_loccookie)
continue;
offset = (char *)(darr[i]) -
(bh->b_data + gfs2_dirent_offset(bh->b_data));
offset /= GFS2_MIN_DIRENT_SIZE;
offset += leaf_nr * sdp->sd_max_dents_per_leaf;
if (offset >= GFS2_USE_HASH_FLAG ||
leaf_nr >= GFS2_USE_HASH_FLAG) {
darr[i]->de_cookie |= GFS2_USE_HASH_FLAG;
if (sort_id < 0)
sort_id = i;
continue;
}
darr[i]->de_cookie &= GFS2_HASH_INDEX_MASK;
darr[i]->de_cookie |= offset;
}
return sort_id;
}
static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx, static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
int *copied, unsigned *depth, int *copied, unsigned *depth,
u64 leaf_no) u64 leaf_no)
...@@ -1304,12 +1377,11 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx, ...@@ -1304,12 +1377,11 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
struct buffer_head *bh; struct buffer_head *bh;
struct gfs2_leaf *lf; struct gfs2_leaf *lf;
unsigned entries = 0, entries2 = 0; unsigned entries = 0, entries2 = 0;
unsigned leaves = 0; unsigned leaves = 0, leaf = 0, offset, sort_offset;
const struct gfs2_dirent **darr, *dent; struct gfs2_dirent **darr, *dent;
struct dirent_gather g; struct dirent_gather g;
struct buffer_head **larr; struct buffer_head **larr;
int leaf = 0; int error, i, need_sort = 0, sort_id;
int error, i;
u64 lfn = leaf_no; u64 lfn = leaf_no;
do { do {
...@@ -1325,6 +1397,11 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx, ...@@ -1325,6 +1397,11 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
brelse(bh); brelse(bh);
} while(lfn); } while(lfn);
if (*depth < GFS2_DIR_MAX_DEPTH || !sdp->sd_args.ar_loccookie) {
need_sort = 1;
sort_offset = 0;
}
if (!entries) if (!entries)
return 0; return 0;
...@@ -1338,8 +1415,8 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx, ...@@ -1338,8 +1415,8 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *)); larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *));
if (!larr) if (!larr)
goto out; goto out;
darr = (const struct gfs2_dirent **)(larr + leaves); darr = (struct gfs2_dirent **)(larr + leaves);
g.pdent = darr; g.pdent = (const struct gfs2_dirent **)darr;
g.offset = 0; g.offset = 0;
lfn = leaf_no; lfn = leaf_no;
...@@ -1350,6 +1427,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx, ...@@ -1350,6 +1427,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
lf = (struct gfs2_leaf *)bh->b_data; lf = (struct gfs2_leaf *)bh->b_data;
lfn = be64_to_cpu(lf->lf_next); lfn = be64_to_cpu(lf->lf_next);
if (lf->lf_entries) { if (lf->lf_entries) {
offset = g.offset;
entries2 += be16_to_cpu(lf->lf_entries); entries2 += be16_to_cpu(lf->lf_entries);
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
gfs2_dirent_gather, NULL, &g); gfs2_dirent_gather, NULL, &g);
...@@ -1367,17 +1445,26 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx, ...@@ -1367,17 +1445,26 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
goto out_free; goto out_free;
} }
error = 0; error = 0;
sort_id = gfs2_set_cookies(sdp, bh, leaf, &darr[offset],
be16_to_cpu(lf->lf_entries));
if (!need_sort && sort_id >= 0) {
need_sort = 1;
sort_offset = offset + sort_id;
}
larr[leaf++] = bh; larr[leaf++] = bh;
} else { } else {
larr[leaf++] = NULL;
brelse(bh); brelse(bh);
} }
} while(lfn); } while(lfn);
BUG_ON(entries2 != entries); BUG_ON(entries2 != entries);
error = do_filldir_main(ip, ctx, darr, entries, copied); error = do_filldir_main(ip, ctx, darr, entries, need_sort ?
sort_offset : entries, copied);
out_free: out_free:
for(i = 0; i < leaf; i++) for(i = 0; i < leaf; i++)
brelse(larr[i]); if (larr[i])
brelse(larr[i]);
kvfree(larr); kvfree(larr);
out: out:
return error; return error;
...@@ -1483,7 +1570,7 @@ int gfs2_dir_read(struct inode *inode, struct dir_context *ctx, ...@@ -1483,7 +1570,7 @@ int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
struct gfs2_inode *dip = GFS2_I(inode); struct gfs2_inode *dip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct dirent_gather g; struct dirent_gather g;
const struct gfs2_dirent **darr, *dent; struct gfs2_dirent **darr, *dent;
struct buffer_head *dibh; struct buffer_head *dibh;
int copied = 0; int copied = 0;
int error; int error;
...@@ -1507,7 +1594,7 @@ int gfs2_dir_read(struct inode *inode, struct dir_context *ctx, ...@@ -1507,7 +1594,7 @@ int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
/* 96 is max number of dirents which can be stuffed into an inode */ /* 96 is max number of dirents which can be stuffed into an inode */
darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_NOFS); darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_NOFS);
if (darr) { if (darr) {
g.pdent = darr; g.pdent = (const struct gfs2_dirent **)darr;
g.offset = 0; g.offset = 0;
dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size, dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,
gfs2_dirent_gather, NULL, &g); gfs2_dirent_gather, NULL, &g);
...@@ -1524,8 +1611,9 @@ int gfs2_dir_read(struct inode *inode, struct dir_context *ctx, ...@@ -1524,8 +1611,9 @@ int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
error = -EIO; error = -EIO;
goto out; goto out;
} }
gfs2_set_cookies(sdp, dibh, 0, darr, dip->i_entries);
error = do_filldir_main(dip, ctx, darr, error = do_filldir_main(dip, ctx, darr,
dip->i_entries, &copied); dip->i_entries, 0, &copied);
out: out:
kfree(darr); kfree(darr);
} }
...@@ -1560,15 +1648,22 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name, ...@@ -1560,15 +1648,22 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name,
dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
if (dent) { if (dent) {
struct inode *inode;
u16 rahead;
if (IS_ERR(dent)) if (IS_ERR(dent))
return ERR_CAST(dent); return ERR_CAST(dent);
dtype = be16_to_cpu(dent->de_type); dtype = be16_to_cpu(dent->de_type);
rahead = be16_to_cpu(dent->de_rahead);
addr = be64_to_cpu(dent->de_inum.no_addr); addr = be64_to_cpu(dent->de_inum.no_addr);
formal_ino = be64_to_cpu(dent->de_inum.no_formal_ino); formal_ino = be64_to_cpu(dent->de_inum.no_formal_ino);
brelse(bh); brelse(bh);
if (fail_on_exist) if (fail_on_exist)
return ERR_PTR(-EEXIST); return ERR_PTR(-EEXIST);
return gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino, 0); inode = gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino, 0);
if (!IS_ERR(inode))
GFS2_I(inode)->i_rahead = rahead;
return inode;
} }
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
......
...@@ -298,9 +298,9 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr) ...@@ -298,9 +298,9 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
gfsflags &= ~GFS2_DIF_TOPDIR; gfsflags &= ~GFS2_DIF_TOPDIR;
if (gfsflags & GFS2_DIF_INHERIT_JDATA) if (gfsflags & GFS2_DIF_INHERIT_JDATA)
gfsflags ^= (GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA); gfsflags ^= (GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA);
return do_gfs2_set_flags(filp, gfsflags, ~0); return do_gfs2_set_flags(filp, gfsflags, ~GFS2_DIF_SYSTEM);
} }
return do_gfs2_set_flags(filp, gfsflags, ~GFS2_DIF_JDATA); return do_gfs2_set_flags(filp, gfsflags, ~(GFS2_DIF_SYSTEM | GFS2_DIF_JDATA));
} }
static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
...@@ -336,8 +336,8 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size) ...@@ -336,8 +336,8 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
size_t blks = (size + sdp->sd_sb.sb_bsize - 1) >> sdp->sd_sb.sb_bsize_shift; size_t blks = (size + sdp->sd_sb.sb_bsize - 1) >> sdp->sd_sb.sb_bsize_shift;
int hint = min_t(size_t, INT_MAX, blks); int hint = min_t(size_t, INT_MAX, blks);
if (hint > atomic_read(&ip->i_res->rs_sizehint)) if (hint > atomic_read(&ip->i_res.rs_sizehint))
atomic_set(&ip->i_res->rs_sizehint, hint); atomic_set(&ip->i_res.rs_sizehint, hint);
} }
/** /**
...@@ -397,14 +397,10 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -397,14 +397,10 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
/* Update file times before taking page lock */ /* Update file times before taking page lock */
file_update_time(vma->vm_file); file_update_time(vma->vm_file);
ret = get_write_access(inode); ret = gfs2_rsqa_alloc(ip);
if (ret) if (ret)
goto out; goto out;
ret = gfs2_rs_alloc(ip);
if (ret)
goto out_write_access;
gfs2_size_hint(vma->vm_file, pos, PAGE_CACHE_SIZE); gfs2_size_hint(vma->vm_file, pos, PAGE_CACHE_SIZE);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
...@@ -486,8 +482,6 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -486,8 +482,6 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
set_page_dirty(page); set_page_dirty(page);
wait_for_stable_page(page); wait_for_stable_page(page);
} }
out_write_access:
put_write_access(inode);
out: out:
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
return block_page_mkwrite_return(ret); return block_page_mkwrite_return(ret);
...@@ -623,7 +617,7 @@ static int gfs2_release(struct inode *inode, struct file *file) ...@@ -623,7 +617,7 @@ static int gfs2_release(struct inode *inode, struct file *file)
if (!(file->f_mode & FMODE_WRITE)) if (!(file->f_mode & FMODE_WRITE))
return 0; return 0;
gfs2_rs_delete(ip, &inode->i_writecount); gfs2_rsqa_delete(ip, &inode->i_writecount);
return 0; return 0;
} }
...@@ -703,7 +697,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -703,7 +697,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct gfs2_inode *ip = GFS2_I(file_inode(file)); struct gfs2_inode *ip = GFS2_I(file_inode(file));
int ret; int ret;
ret = gfs2_rs_alloc(ip); ret = gfs2_rsqa_alloc(ip);
if (ret) if (ret)
return ret; return ret;
...@@ -938,13 +932,14 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t le ...@@ -938,13 +932,14 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t le
if (ret) if (ret)
goto out_unlock; goto out_unlock;
ret = gfs2_rs_alloc(ip); ret = gfs2_rsqa_alloc(ip);
if (ret) if (ret)
goto out_putw; goto out_putw;
ret = __gfs2_fallocate(file, mode, offset, len); ret = __gfs2_fallocate(file, mode, offset, len);
if (ret) if (ret)
gfs2_rs_deltree(ip->i_res); gfs2_rs_deltree(&ip->i_res);
out_putw: out_putw:
put_write_access(inode); put_write_access(inode);
out_unlock: out_unlock:
...@@ -962,7 +957,7 @@ static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe, ...@@ -962,7 +957,7 @@ static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe,
int error; int error;
struct gfs2_inode *ip = GFS2_I(out->f_mapping->host); struct gfs2_inode *ip = GFS2_I(out->f_mapping->host);
error = gfs2_rs_alloc(ip); error = gfs2_rsqa_alloc(ip);
if (error) if (error)
return (ssize_t)error; return (ssize_t)error;
...@@ -1018,7 +1013,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -1018,7 +1013,7 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
struct gfs2_inode *ip = GFS2_I(file_inode(file)); struct gfs2_inode *ip = GFS2_I(file_inode(file));
struct gfs2_glock *gl; struct gfs2_glock *gl;
unsigned int state; unsigned int state;
int flags; u16 flags;
int error = 0; int error = 0;
int sleeptime; int sleeptime;
...@@ -1032,7 +1027,10 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -1032,7 +1027,10 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
if (fl_gh->gh_state == state) if (fl_gh->gh_state == state)
goto out; goto out;
locks_lock_file_wait(file, locks_lock_file_wait(file,
&(struct file_lock){.fl_type = F_UNLCK}); &(struct file_lock) {
.fl_type = F_UNLCK,
.fl_flags = FL_FLOCK
});
gfs2_glock_dq(fl_gh); gfs2_glock_dq(fl_gh);
gfs2_holder_reinit(state, flags, fl_gh); gfs2_holder_reinit(state, flags, fl_gh);
} else { } else {
......
...@@ -446,7 +446,7 @@ __acquires(&gl->gl_lockref.lock) ...@@ -446,7 +446,7 @@ __acquires(&gl->gl_lockref.lock)
{ {
const struct gfs2_glock_operations *glops = gl->gl_ops; const struct gfs2_glock_operations *glops = gl->gl_ops;
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
unsigned int lck_flags = gh ? gh->gh_flags : 0; unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0);
int ret; int ret;
lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP | lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP |
...@@ -750,7 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, ...@@ -750,7 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
* *
*/ */
void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, u16 flags,
struct gfs2_holder *gh) struct gfs2_holder *gh)
{ {
INIT_LIST_HEAD(&gh->gh_list); INIT_LIST_HEAD(&gh->gh_list);
...@@ -774,7 +774,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, ...@@ -774,7 +774,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
* *
*/ */
void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh) void gfs2_holder_reinit(unsigned int state, u16 flags, struct gfs2_holder *gh)
{ {
gh->gh_state = state; gh->gh_state = state;
gh->gh_flags = flags; gh->gh_flags = flags;
...@@ -1080,7 +1080,7 @@ void gfs2_glock_dq_uninit(struct gfs2_holder *gh) ...@@ -1080,7 +1080,7 @@ void gfs2_glock_dq_uninit(struct gfs2_holder *gh)
int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
const struct gfs2_glock_operations *glops, const struct gfs2_glock_operations *glops,
unsigned int state, int flags, struct gfs2_holder *gh) unsigned int state, u16 flags, struct gfs2_holder *gh)
{ {
struct gfs2_glock *gl; struct gfs2_glock *gl;
int error; int error;
...@@ -1417,14 +1417,14 @@ static struct shrinker glock_shrinker = { ...@@ -1417,14 +1417,14 @@ static struct shrinker glock_shrinker = {
static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp) static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp)
{ {
struct gfs2_glock *gl; struct gfs2_glock *gl;
struct rhash_head *pos, *next; struct rhash_head *pos;
const struct bucket_table *tbl; const struct bucket_table *tbl;
int i; int i;
rcu_read_lock(); rcu_read_lock();
tbl = rht_dereference_rcu(gl_hash_table.tbl, &gl_hash_table); tbl = rht_dereference_rcu(gl_hash_table.tbl, &gl_hash_table);
for (i = 0; i < tbl->size; i++) { for (i = 0; i < tbl->size; i++) {
rht_for_each_entry_safe(gl, pos, next, tbl, i, gl_node) { rht_for_each_entry_rcu(gl, pos, tbl, i, gl_node) {
if ((gl->gl_name.ln_sbd == sdp) && if ((gl->gl_name.ln_sbd == sdp) &&
lockref_get_not_dead(&gl->gl_lockref)) lockref_get_not_dead(&gl->gl_lockref))
examiner(gl); examiner(gl);
...@@ -1506,7 +1506,9 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) ...@@ -1506,7 +1506,9 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp)
flush_workqueue(glock_workqueue); flush_workqueue(glock_workqueue);
glock_hash_walk(clear_glock, sdp); glock_hash_walk(clear_glock, sdp);
flush_workqueue(glock_workqueue); flush_workqueue(glock_workqueue);
wait_event(sdp->sd_glock_wait, atomic_read(&sdp->sd_glock_disposal) == 0); wait_event_timeout(sdp->sd_glock_wait,
atomic_read(&sdp->sd_glock_disposal) == 0,
HZ * 600);
glock_hash_walk(dump_glock_func, sdp); glock_hash_walk(dump_glock_func, sdp);
} }
...@@ -1539,7 +1541,7 @@ static const char *state2str(unsigned state) ...@@ -1539,7 +1541,7 @@ static const char *state2str(unsigned state)
return "??"; return "??";
} }
static const char *hflags2str(char *buf, unsigned flags, unsigned long iflags) static const char *hflags2str(char *buf, u16 flags, unsigned long iflags)
{ {
char *p = buf; char *p = buf;
if (flags & LM_FLAG_TRY) if (flags & LM_FLAG_TRY)
......
...@@ -79,15 +79,15 @@ enum { ...@@ -79,15 +79,15 @@ enum {
* requested had acquired and released the lock. * requested had acquired and released the lock.
*/ */
#define LM_FLAG_TRY 0x00000001 #define LM_FLAG_TRY 0x0001
#define LM_FLAG_TRY_1CB 0x00000002 #define LM_FLAG_TRY_1CB 0x0002
#define LM_FLAG_NOEXP 0x00000004 #define LM_FLAG_NOEXP 0x0004
#define LM_FLAG_ANY 0x00000008 #define LM_FLAG_ANY 0x0008
#define LM_FLAG_PRIORITY 0x00000010 #define LM_FLAG_PRIORITY 0x0010
#define GL_ASYNC 0x00000040 #define GL_ASYNC 0x0040
#define GL_EXACT 0x00000080 #define GL_EXACT 0x0080
#define GL_SKIP 0x00000100 #define GL_SKIP 0x0100
#define GL_NOCACHE 0x00000400 #define GL_NOCACHE 0x0400
/* /*
* lm_async_cb return flags * lm_async_cb return flags
...@@ -183,8 +183,8 @@ extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, ...@@ -183,8 +183,8 @@ extern int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
int create, struct gfs2_glock **glp); int create, struct gfs2_glock **glp);
extern void gfs2_glock_put(struct gfs2_glock *gl); extern void gfs2_glock_put(struct gfs2_glock *gl);
extern void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, extern void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state,
unsigned flags, struct gfs2_holder *gh); u16 flags, struct gfs2_holder *gh);
extern void gfs2_holder_reinit(unsigned int state, unsigned flags, extern void gfs2_holder_reinit(unsigned int state, u16 flags,
struct gfs2_holder *gh); struct gfs2_holder *gh);
extern void gfs2_holder_uninit(struct gfs2_holder *gh); extern void gfs2_holder_uninit(struct gfs2_holder *gh);
extern int gfs2_glock_nq(struct gfs2_holder *gh); extern int gfs2_glock_nq(struct gfs2_holder *gh);
...@@ -195,7 +195,7 @@ extern void gfs2_glock_dq_wait(struct gfs2_holder *gh); ...@@ -195,7 +195,7 @@ extern void gfs2_glock_dq_wait(struct gfs2_holder *gh);
extern void gfs2_glock_dq_uninit(struct gfs2_holder *gh); extern void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
extern int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, extern int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
const struct gfs2_glock_operations *glops, const struct gfs2_glock_operations *glops,
unsigned int state, int flags, unsigned int state, u16 flags,
struct gfs2_holder *gh); struct gfs2_holder *gh);
extern int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); extern int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
extern void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); extern void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
...@@ -215,7 +215,7 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...); ...@@ -215,7 +215,7 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...);
*/ */
static inline int gfs2_glock_nq_init(struct gfs2_glock *gl, static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
unsigned int state, int flags, unsigned int state, u16 flags,
struct gfs2_holder *gh) struct gfs2_holder *gh)
{ {
int error; int error;
......
...@@ -259,8 +259,8 @@ struct gfs2_holder { ...@@ -259,8 +259,8 @@ struct gfs2_holder {
struct gfs2_glock *gh_gl; struct gfs2_glock *gh_gl;
struct pid *gh_owner_pid; struct pid *gh_owner_pid;
unsigned int gh_state; u16 gh_flags;
unsigned gh_flags; u16 gh_state;
int gh_error; int gh_error;
unsigned long gh_iflags; /* HIF_... */ unsigned long gh_iflags; /* HIF_... */
...@@ -270,6 +270,13 @@ struct gfs2_holder { ...@@ -270,6 +270,13 @@ struct gfs2_holder {
/* Number of quota types we support */ /* Number of quota types we support */
#define GFS2_MAXQUOTAS 2 #define GFS2_MAXQUOTAS 2
struct gfs2_qadata { /* quota allocation data */
/* Quota stuff */
struct gfs2_quota_data *qa_qd[2 * GFS2_MAXQUOTAS];
struct gfs2_holder qa_qd_ghs[2 * GFS2_MAXQUOTAS];
unsigned int qa_qd_num;
};
/* Resource group multi-block reservation, in order of appearance: /* Resource group multi-block reservation, in order of appearance:
Step 1. Function prepares to write, allocates a mb, sets the size hint. Step 1. Function prepares to write, allocates a mb, sets the size hint.
...@@ -288,11 +295,6 @@ struct gfs2_blkreserv { ...@@ -288,11 +295,6 @@ struct gfs2_blkreserv {
struct gfs2_rbm rs_rbm; /* Start of reservation */ struct gfs2_rbm rs_rbm; /* Start of reservation */
u32 rs_free; /* how many blocks are still free */ u32 rs_free; /* how many blocks are still free */
u64 rs_inum; /* Inode number for reservation */ u64 rs_inum; /* Inode number for reservation */
/* ancillary quota stuff */
struct gfs2_quota_data *rs_qa_qd[2 * GFS2_MAXQUOTAS];
struct gfs2_holder rs_qa_qd_ghs[2 * GFS2_MAXQUOTAS];
unsigned int rs_qa_qd_num;
}; };
/* /*
...@@ -391,7 +393,8 @@ struct gfs2_inode { ...@@ -391,7 +393,8 @@ struct gfs2_inode {
struct gfs2_glock *i_gl; /* Move into i_gh? */ struct gfs2_glock *i_gl; /* Move into i_gh? */
struct gfs2_holder i_iopen_gh; struct gfs2_holder i_iopen_gh;
struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_holder i_gh; /* for prepare/commit_write only */
struct gfs2_blkreserv *i_res; /* rgrp multi-block reservation */ struct gfs2_qadata *i_qadata; /* quota allocation data */
struct gfs2_blkreserv i_res; /* rgrp multi-block reservation */
struct gfs2_rgrpd *i_rgd; struct gfs2_rgrpd *i_rgd;
u64 i_goal; /* goal block for allocations */ u64 i_goal; /* goal block for allocations */
struct rw_semaphore i_rw_mutex; struct rw_semaphore i_rw_mutex;
...@@ -402,6 +405,7 @@ struct gfs2_inode { ...@@ -402,6 +405,7 @@ struct gfs2_inode {
u32 i_diskflags; u32 i_diskflags;
u8 i_height; u8 i_height;
u8 i_depth; u8 i_depth;
u16 i_rahead;
}; };
/* /*
...@@ -558,6 +562,8 @@ struct gfs2_args { ...@@ -558,6 +562,8 @@ struct gfs2_args {
unsigned int ar_errors:2; /* errors=withdraw | panic */ unsigned int ar_errors:2; /* errors=withdraw | panic */
unsigned int ar_nobarrier:1; /* do not send barriers */ unsigned int ar_nobarrier:1; /* do not send barriers */
unsigned int ar_rgrplvb:1; /* use lvbs for rgrp info */ unsigned int ar_rgrplvb:1; /* use lvbs for rgrp info */
unsigned int ar_loccookie:1; /* use location based readdir
cookies */
int ar_commit; /* Commit interval */ int ar_commit; /* Commit interval */
int ar_statfs_quantum; /* The fast statfs interval */ int ar_statfs_quantum; /* The fast statfs interval */
int ar_quota_quantum; /* The quota interval */ int ar_quota_quantum; /* The quota interval */
...@@ -685,6 +691,7 @@ struct gfs2_sbd { ...@@ -685,6 +691,7 @@ struct gfs2_sbd {
u64 sd_heightsize[GFS2_MAX_META_HEIGHT + 1]; u64 sd_heightsize[GFS2_MAX_META_HEIGHT + 1];
u32 sd_max_jheight; /* Max height of journaled file's meta tree */ u32 sd_max_jheight; /* Max height of journaled file's meta tree */
u64 sd_jheightsize[GFS2_MAX_META_HEIGHT + 1]; u64 sd_jheightsize[GFS2_MAX_META_HEIGHT + 1];
u32 sd_max_dents_per_leaf; /* Max number of dirents in a leaf block */
struct gfs2_args sd_args; /* Mount arguments */ struct gfs2_args sd_args; /* Mount arguments */
struct gfs2_tune sd_tune; /* Filesystem tuning structure */ struct gfs2_tune sd_tune; /* Filesystem tuning structure */
......
...@@ -191,13 +191,13 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, ...@@ -191,13 +191,13 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
fail_refresh: fail_refresh:
ip->i_iopen_gh.gh_flags |= GL_NOCACHE; ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
ip->i_iopen_gh.gh_gl->gl_object = NULL; ip->i_iopen_gh.gh_gl->gl_object = NULL;
gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_dq_wait(&ip->i_iopen_gh);
gfs2_holder_uninit(&ip->i_iopen_gh);
fail_iopen: fail_iopen:
if (io_gl) if (io_gl)
gfs2_glock_put(io_gl); gfs2_glock_put(io_gl);
fail_put: fail_put:
ip->i_gl->gl_object = NULL; ip->i_gl->gl_object = NULL;
gfs2_glock_put(ip->i_gl);
fail: fail:
iget_failed(inode); iget_failed(inode);
return ERR_PTR(error); return ERR_PTR(error);
...@@ -593,7 +593,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -593,7 +593,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
struct gfs2_inode *dip = GFS2_I(dir), *ip; struct gfs2_inode *dip = GFS2_I(dir), *ip;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_glock *io_gl; struct gfs2_glock *io_gl;
int error, free_vfs_inode = 0; int error, free_vfs_inode = 1;
u32 aflags = 0; u32 aflags = 0;
unsigned blocks = 1; unsigned blocks = 1;
struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, }; struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, };
...@@ -601,7 +601,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -601,7 +601,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (!name->len || name->len > GFS2_FNAMESIZE) if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG; return -ENAMETOOLONG;
error = gfs2_rs_alloc(dip); error = gfs2_rsqa_alloc(dip);
if (error) if (error)
return error; return error;
...@@ -650,10 +650,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -650,10 +650,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
error = posix_acl_create(dir, &mode, &default_acl, &acl); error = posix_acl_create(dir, &mode, &default_acl, &acl);
if (error) if (error)
goto fail_free_vfs_inode; goto fail_gunlock;
ip = GFS2_I(inode); ip = GFS2_I(inode);
error = gfs2_rs_alloc(ip); error = gfs2_rsqa_alloc(ip);
if (error) if (error)
goto fail_free_acls; goto fail_free_acls;
...@@ -685,6 +685,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -685,6 +685,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
ip->i_entries = 2; ip->i_entries = 2;
break; break;
} }
/* Force SYSTEM flag on all files and subdirs of a SYSTEM directory */
if (dip->i_diskflags & GFS2_DIF_SYSTEM)
ip->i_diskflags |= GFS2_DIF_SYSTEM;
gfs2_set_inode_flags(inode); gfs2_set_inode_flags(inode);
if ((GFS2_I(d_inode(sdp->sd_root_dir)) == dip) || if ((GFS2_I(d_inode(sdp->sd_root_dir)) == dip) ||
...@@ -733,6 +738,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -733,6 +738,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
gfs2_set_iop(inode); gfs2_set_iop(inode);
insert_inode_hash(inode); insert_inode_hash(inode);
free_vfs_inode = 0; /* After this point, the inode is no longer
considered free. Any failures need to undo
the gfs2 structures. */
if (default_acl) { if (default_acl) {
error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
posix_acl_release(default_acl); posix_acl_release(default_acl);
...@@ -766,24 +774,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -766,24 +774,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
return error; return error;
fail_gunlock3: fail_gunlock3:
gfs2_glock_dq_uninit(ghs + 1); gfs2_glock_dq_uninit(&ip->i_iopen_gh);
if (ip->i_gl) gfs2_glock_put(io_gl);
gfs2_glock_put(ip->i_gl);
goto fail_gunlock;
fail_gunlock2: fail_gunlock2:
gfs2_glock_dq_uninit(ghs + 1); gfs2_glock_dq_uninit(ghs + 1);
fail_free_inode: fail_free_inode:
if (ip->i_gl) if (ip->i_gl)
gfs2_glock_put(ip->i_gl); gfs2_glock_put(ip->i_gl);
gfs2_rs_delete(ip, NULL); gfs2_rsqa_delete(ip, NULL);
fail_free_acls: fail_free_acls:
if (default_acl) if (default_acl)
posix_acl_release(default_acl); posix_acl_release(default_acl);
if (acl) if (acl)
posix_acl_release(acl); posix_acl_release(acl);
fail_free_vfs_inode:
free_vfs_inode = 1;
fail_gunlock: fail_gunlock:
gfs2_dir_no_add(&da); gfs2_dir_no_add(&da);
gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs);
...@@ -898,7 +901,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -898,7 +901,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
return -EPERM; return -EPERM;
error = gfs2_rs_alloc(dip); error = gfs2_rsqa_alloc(dip);
if (error) if (error)
return error; return error;
...@@ -1371,7 +1374,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1371,7 +1374,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (error) if (error)
return error; return error;
error = gfs2_rs_alloc(ndip); error = gfs2_rsqa_alloc(ndip);
if (error) if (error)
return error; return error;
...@@ -1860,11 +1863,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1860,11 +1863,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid)) if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid))
ogid = ngid = NO_GID_QUOTA_CHANGE; ogid = ngid = NO_GID_QUOTA_CHANGE;
error = get_write_access(inode); error = gfs2_rsqa_alloc(ip);
if (error)
return error;
error = gfs2_rs_alloc(ip);
if (error) if (error)
goto out; goto out;
...@@ -1904,7 +1903,6 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1904,7 +1903,6 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
out_gunlock_q: out_gunlock_q:
gfs2_quota_unlock(ip); gfs2_quota_unlock(ip);
out: out:
put_write_access(inode);
return error; return error;
} }
...@@ -1926,7 +1924,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1926,7 +1924,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
struct gfs2_holder i_gh; struct gfs2_holder i_gh;
int error; int error;
error = gfs2_rs_alloc(ip); error = gfs2_rsqa_alloc(ip);
if (error) if (error)
return error; return error;
...@@ -2008,7 +2006,7 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, ...@@ -2008,7 +2006,7 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name,
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh); ret = gfs2_glock_nq(&gh);
if (ret == 0) { if (ret == 0) {
ret = gfs2_rs_alloc(ip); ret = gfs2_rsqa_alloc(ip);
if (ret == 0) if (ret == 0)
ret = generic_setxattr(dentry, name, data, size, flags); ret = generic_setxattr(dentry, name, data, size, flags);
gfs2_glock_dq(&gh); gfs2_glock_dq(&gh);
...@@ -2049,7 +2047,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) ...@@ -2049,7 +2047,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name)
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh); ret = gfs2_glock_nq(&gh);
if (ret == 0) { if (ret == 0) {
ret = gfs2_rs_alloc(ip); ret = gfs2_rsqa_alloc(ip);
if (ret == 0) if (ret == 0)
ret = generic_removexattr(dentry, name); ret = generic_removexattr(dentry, name);
gfs2_glock_dq(&gh); gfs2_glock_dq(&gh);
......
...@@ -716,6 +716,9 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ...@@ -716,6 +716,9 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
} }
trace_gfs2_log_flush(sdp, 1); trace_gfs2_log_flush(sdp, 1);
if (type == SHUTDOWN_FLUSH)
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
sdp->sd_log_flush_head = sdp->sd_log_head; sdp->sd_log_flush_head = sdp->sd_log_head;
sdp->sd_log_flush_wrapped = 0; sdp->sd_log_flush_wrapped = 0;
tr = sdp->sd_log_tr; tr = sdp->sd_log_tr;
......
...@@ -41,7 +41,9 @@ static void gfs2_init_inode_once(void *foo) ...@@ -41,7 +41,9 @@ static void gfs2_init_inode_once(void *foo)
inode_init_once(&ip->i_inode); inode_init_once(&ip->i_inode);
init_rwsem(&ip->i_rw_mutex); init_rwsem(&ip->i_rw_mutex);
INIT_LIST_HEAD(&ip->i_trunc_list); INIT_LIST_HEAD(&ip->i_trunc_list);
ip->i_res = NULL; ip->i_qadata = NULL;
memset(&ip->i_res, 0, sizeof(ip->i_res));
RB_CLEAR_NODE(&ip->i_res.rs_node);
ip->i_hash_cache = NULL; ip->i_hash_cache = NULL;
} }
...@@ -135,10 +137,10 @@ static int __init init_gfs2_fs(void) ...@@ -135,10 +137,10 @@ static int __init init_gfs2_fs(void)
if (!gfs2_quotad_cachep) if (!gfs2_quotad_cachep)
goto fail; goto fail;
gfs2_rsrv_cachep = kmem_cache_create("gfs2_mblk", gfs2_qadata_cachep = kmem_cache_create("gfs2_qadata",
sizeof(struct gfs2_blkreserv), sizeof(struct gfs2_qadata),
0, 0, NULL); 0, 0, NULL);
if (!gfs2_rsrv_cachep) if (!gfs2_qadata_cachep)
goto fail; goto fail;
register_shrinker(&gfs2_qd_shrinker); register_shrinker(&gfs2_qd_shrinker);
...@@ -193,8 +195,8 @@ static int __init init_gfs2_fs(void) ...@@ -193,8 +195,8 @@ static int __init init_gfs2_fs(void)
unregister_shrinker(&gfs2_qd_shrinker); unregister_shrinker(&gfs2_qd_shrinker);
gfs2_glock_exit(); gfs2_glock_exit();
if (gfs2_rsrv_cachep) if (gfs2_qadata_cachep)
kmem_cache_destroy(gfs2_rsrv_cachep); kmem_cache_destroy(gfs2_qadata_cachep);
if (gfs2_quotad_cachep) if (gfs2_quotad_cachep)
kmem_cache_destroy(gfs2_quotad_cachep); kmem_cache_destroy(gfs2_quotad_cachep);
...@@ -238,7 +240,7 @@ static void __exit exit_gfs2_fs(void) ...@@ -238,7 +240,7 @@ static void __exit exit_gfs2_fs(void)
rcu_barrier(); rcu_barrier();
mempool_destroy(gfs2_page_pool); mempool_destroy(gfs2_page_pool);
kmem_cache_destroy(gfs2_rsrv_cachep); kmem_cache_destroy(gfs2_qadata_cachep);
kmem_cache_destroy(gfs2_quotad_cachep); kmem_cache_destroy(gfs2_quotad_cachep);
kmem_cache_destroy(gfs2_rgrpd_cachep); kmem_cache_destroy(gfs2_rgrpd_cachep);
kmem_cache_destroy(gfs2_bufdata_cachep); kmem_cache_destroy(gfs2_bufdata_cachep);
......
...@@ -187,6 +187,52 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) ...@@ -187,6 +187,52 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
return bh; return bh;
} }
static void gfs2_meta_read_endio(struct bio *bio)
{
struct bio_vec *bvec;
int i;
bio_for_each_segment_all(bvec, bio, i) {
struct page *page = bvec->bv_page;
struct buffer_head *bh = page_buffers(page);
unsigned int len = bvec->bv_len;
while (bh_offset(bh) < bvec->bv_offset)
bh = bh->b_this_page;
do {
struct buffer_head *next = bh->b_this_page;
len -= bh->b_size;
bh->b_end_io(bh, !bio->bi_error);
bh = next;
} while (bh && len);
}
bio_put(bio);
}
/*
* Submit several consecutive buffer head I/O requests as a single bio I/O
* request. (See submit_bh_wbc.)
*/
static void gfs2_submit_bhs(int rw, struct buffer_head *bhs[], int num)
{
struct buffer_head *bh = bhs[0];
struct bio *bio;
int i;
if (!num)
return;
bio = bio_alloc(GFP_NOIO, num);
bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_bdev = bh->b_bdev;
for (i = 0; i < num; i++) {
bh = bhs[i];
bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
}
bio->bi_end_io = gfs2_meta_read_endio;
submit_bio(rw, bio);
}
/** /**
* gfs2_meta_read - Read a block from disk * gfs2_meta_read - Read a block from disk
* @gl: The glock covering the block * @gl: The glock covering the block
...@@ -198,10 +244,11 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) ...@@ -198,10 +244,11 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
*/ */
int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
struct buffer_head **bhp) int rahead, struct buffer_head **bhp)
{ {
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
struct buffer_head *bh; struct buffer_head *bh, *bhs[2];
int num = 0;
if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) { if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
*bhp = NULL; *bhp = NULL;
...@@ -213,14 +260,31 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, ...@@ -213,14 +260,31 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
lock_buffer(bh); lock_buffer(bh);
if (buffer_uptodate(bh)) { if (buffer_uptodate(bh)) {
unlock_buffer(bh); unlock_buffer(bh);
return 0; flags &= ~DIO_WAIT;
} else {
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
bhs[num++] = bh;
} }
bh->b_end_io = end_buffer_read_sync;
get_bh(bh); if (rahead) {
submit_bh(READ_SYNC | REQ_META | REQ_PRIO, bh); bh = gfs2_getbuf(gl, blkno + 1, CREATE);
lock_buffer(bh);
if (buffer_uptodate(bh)) {
unlock_buffer(bh);
brelse(bh);
} else {
bh->b_end_io = end_buffer_read_sync;
bhs[num++] = bh;
}
}
gfs2_submit_bhs(READ_SYNC | REQ_META | REQ_PRIO, bhs, num);
if (!(flags & DIO_WAIT)) if (!(flags & DIO_WAIT))
return 0; return 0;
bh = *bhp;
wait_on_buffer(bh); wait_on_buffer(bh);
if (unlikely(!buffer_uptodate(bh))) { if (unlikely(!buffer_uptodate(bh))) {
struct gfs2_trans *tr = current->journal_info; struct gfs2_trans *tr = current->journal_info;
...@@ -341,8 +405,12 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, ...@@ -341,8 +405,12 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
struct buffer_head *bh; struct buffer_head *bh;
int ret = 0; int ret = 0;
u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI; u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
int rahead = 0;
if (num == ip->i_no_addr)
rahead = ip->i_rahead;
ret = gfs2_meta_read(gl, num, DIO_WAIT, &bh); ret = gfs2_meta_read(gl, num, DIO_WAIT, rahead, &bh);
if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) { if (ret == 0 && gfs2_metatype_check(sdp, bh, mtype)) {
brelse(bh); brelse(bh);
ret = -EIO; ret = -EIO;
......
...@@ -53,7 +53,7 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping) ...@@ -53,7 +53,7 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping)
extern struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno); extern struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
struct buffer_head **bhp); int rahead, struct buffer_head **bhp);
extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh); extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno,
int create); int create);
......
...@@ -352,6 +352,9 @@ static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent) ...@@ -352,6 +352,9 @@ static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent)
sdp->sd_jheightsize[x] = ~0; sdp->sd_jheightsize[x] = ~0;
gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
sdp->sd_max_dents_per_leaf = (sdp->sd_sb.sb_bsize -
sizeof(struct gfs2_leaf)) /
GFS2_MIN_DIRENT_SIZE;
return 0; return 0;
} }
...@@ -910,8 +913,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ...@@ -910,8 +913,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
fail_ut_i: fail_ut_i:
iput(sdp->sd_sc_inode); iput(sdp->sd_sc_inode);
fail: fail:
if (pn) iput(pn);
iput(pn);
return error; return error;
} }
......
...@@ -388,7 +388,7 @@ static int bh_get(struct gfs2_quota_data *qd) ...@@ -388,7 +388,7 @@ static int bh_get(struct gfs2_quota_data *qd)
error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0); error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0);
if (error) if (error)
goto fail; goto fail;
error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh); error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, 0, &bh);
if (error) if (error)
goto fail; goto fail;
error = -EIO; error = -EIO;
...@@ -527,37 +527,70 @@ static void qdsb_put(struct gfs2_quota_data *qd) ...@@ -527,37 +527,70 @@ static void qdsb_put(struct gfs2_quota_data *qd)
qd_put(qd); qd_put(qd);
} }
/**
* gfs2_qa_alloc - make sure we have a quota allocations data structure,
* if necessary
* @ip: the inode for this reservation
*/
int gfs2_qa_alloc(struct gfs2_inode *ip)
{
int error = 0;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return 0;
down_write(&ip->i_rw_mutex);
if (ip->i_qadata == NULL) {
ip->i_qadata = kmem_cache_zalloc(gfs2_qadata_cachep, GFP_NOFS);
if (!ip->i_qadata)
error = -ENOMEM;
}
up_write(&ip->i_rw_mutex);
return error;
}
void gfs2_qa_delete(struct gfs2_inode *ip, atomic_t *wcount)
{
down_write(&ip->i_rw_mutex);
if (ip->i_qadata && ((wcount == NULL) || (atomic_read(wcount) <= 1))) {
kmem_cache_free(gfs2_qadata_cachep, ip->i_qadata);
ip->i_qadata = NULL;
}
up_write(&ip->i_rw_mutex);
}
int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_quota_data **qd; struct gfs2_quota_data **qd;
int error; int error;
if (ip->i_res == NULL) { if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
error = gfs2_rs_alloc(ip); return 0;
if (ip->i_qadata == NULL) {
error = gfs2_rsqa_alloc(ip);
if (error) if (error)
return error; return error;
} }
qd = ip->i_res->rs_qa_qd; qd = ip->i_qadata->qa_qd;
if (gfs2_assert_warn(sdp, !ip->i_res->rs_qa_qd_num) || if (gfs2_assert_warn(sdp, !ip->i_qadata->qa_qd_num) ||
gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags))) gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)))
return -EIO; return -EIO;
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return 0;
error = qdsb_get(sdp, make_kqid_uid(ip->i_inode.i_uid), qd); error = qdsb_get(sdp, make_kqid_uid(ip->i_inode.i_uid), qd);
if (error) if (error)
goto out; goto out;
ip->i_res->rs_qa_qd_num++; ip->i_qadata->qa_qd_num++;
qd++; qd++;
error = qdsb_get(sdp, make_kqid_gid(ip->i_inode.i_gid), qd); error = qdsb_get(sdp, make_kqid_gid(ip->i_inode.i_gid), qd);
if (error) if (error)
goto out; goto out;
ip->i_res->rs_qa_qd_num++; ip->i_qadata->qa_qd_num++;
qd++; qd++;
if (!uid_eq(uid, NO_UID_QUOTA_CHANGE) && if (!uid_eq(uid, NO_UID_QUOTA_CHANGE) &&
...@@ -565,7 +598,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) ...@@ -565,7 +598,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
error = qdsb_get(sdp, make_kqid_uid(uid), qd); error = qdsb_get(sdp, make_kqid_uid(uid), qd);
if (error) if (error)
goto out; goto out;
ip->i_res->rs_qa_qd_num++; ip->i_qadata->qa_qd_num++;
qd++; qd++;
} }
...@@ -574,7 +607,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) ...@@ -574,7 +607,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
error = qdsb_get(sdp, make_kqid_gid(gid), qd); error = qdsb_get(sdp, make_kqid_gid(gid), qd);
if (error) if (error)
goto out; goto out;
ip->i_res->rs_qa_qd_num++; ip->i_qadata->qa_qd_num++;
qd++; qd++;
} }
...@@ -587,17 +620,17 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) ...@@ -587,17 +620,17 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
void gfs2_quota_unhold(struct gfs2_inode *ip) void gfs2_quota_unhold(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
unsigned int x; u32 x;
if (ip->i_res == NULL) if (ip->i_qadata == NULL)
return; return;
gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)); gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) { for (x = 0; x < ip->i_qadata->qa_qd_num; x++) {
qdsb_put(ip->i_res->rs_qa_qd[x]); qdsb_put(ip->i_qadata->qa_qd[x]);
ip->i_res->rs_qa_qd[x] = NULL; ip->i_qadata->qa_qd[x] = NULL;
} }
ip->i_res->rs_qa_qd_num = 0; ip->i_qadata->qa_qd_num = 0;
} }
static int sort_qd(const void *a, const void *b) static int sort_qd(const void *a, const void *b)
...@@ -843,7 +876,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -843,7 +876,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
unsigned int nalloc = 0, blocks; unsigned int nalloc = 0, blocks;
int error; int error;
error = gfs2_rs_alloc(ip); error = gfs2_rsqa_alloc(ip);
if (error) if (error)
return error; return error;
...@@ -1003,23 +1036,23 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) ...@@ -1003,23 +1036,23 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
unsigned int x; u32 x;
int error = 0; int error = 0;
error = gfs2_quota_hold(ip, uid, gid);
if (error)
return error;
if (capable(CAP_SYS_RESOURCE) || if (capable(CAP_SYS_RESOURCE) ||
sdp->sd_args.ar_quota != GFS2_QUOTA_ON) sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
return 0; return 0;
sort(ip->i_res->rs_qa_qd, ip->i_res->rs_qa_qd_num, error = gfs2_quota_hold(ip, uid, gid);
if (error)
return error;
sort(ip->i_qadata->qa_qd, ip->i_qadata->qa_qd_num,
sizeof(struct gfs2_quota_data *), sort_qd, NULL); sizeof(struct gfs2_quota_data *), sort_qd, NULL);
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) { for (x = 0; x < ip->i_qadata->qa_qd_num; x++) {
qd = ip->i_res->rs_qa_qd[x]; qd = ip->i_qadata->qa_qd[x];
error = do_glock(qd, NO_FORCE, &ip->i_res->rs_qa_qd_ghs[x]); error = do_glock(qd, NO_FORCE, &ip->i_qadata->qa_qd_ghs[x]);
if (error) if (error)
break; break;
} }
...@@ -1028,7 +1061,7 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) ...@@ -1028,7 +1061,7 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
set_bit(GIF_QD_LOCKED, &ip->i_flags); set_bit(GIF_QD_LOCKED, &ip->i_flags);
else { else {
while (x--) while (x--)
gfs2_glock_dq_uninit(&ip->i_res->rs_qa_qd_ghs[x]); gfs2_glock_dq_uninit(&ip->i_qadata->qa_qd_ghs[x]);
gfs2_quota_unhold(ip); gfs2_quota_unhold(ip);
} }
...@@ -1076,20 +1109,20 @@ void gfs2_quota_unlock(struct gfs2_inode *ip) ...@@ -1076,20 +1109,20 @@ void gfs2_quota_unlock(struct gfs2_inode *ip)
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_quota_data *qda[4]; struct gfs2_quota_data *qda[4];
unsigned int count = 0; unsigned int count = 0;
unsigned int x; u32 x;
int found; int found;
if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags)) if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags))
goto out; goto out;
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) { for (x = 0; x < ip->i_qadata->qa_qd_num; x++) {
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
int sync; int sync;
qd = ip->i_res->rs_qa_qd[x]; qd = ip->i_qadata->qa_qd[x];
sync = need_sync(qd); sync = need_sync(qd);
gfs2_glock_dq_uninit(&ip->i_res->rs_qa_qd_ghs[x]); gfs2_glock_dq_uninit(&ip->i_qadata->qa_qd_ghs[x]);
if (!sync) if (!sync)
continue; continue;
...@@ -1158,7 +1191,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, ...@@ -1158,7 +1191,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
s64 value, warn, limit; s64 value, warn, limit;
unsigned int x; u32 x;
int error = 0; int error = 0;
ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */ ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */
...@@ -1168,8 +1201,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, ...@@ -1168,8 +1201,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON) if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
return 0; return 0;
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) { for (x = 0; x < ip->i_qadata->qa_qd_num; x++) {
qd = ip->i_res->rs_qa_qd[x]; qd = ip->i_qadata->qa_qd[x];
if (!(qid_eq(qd->qd_id, make_kqid_uid(uid)) || if (!(qid_eq(qd->qd_id, make_kqid_uid(uid)) ||
qid_eq(qd->qd_id, make_kqid_gid(gid)))) qid_eq(qd->qd_id, make_kqid_gid(gid))))
...@@ -1216,15 +1249,17 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change, ...@@ -1216,15 +1249,17 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
kuid_t uid, kgid_t gid) kuid_t uid, kgid_t gid)
{ {
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
unsigned int x; u32 x;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change)) if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON ||
gfs2_assert_warn(sdp, change))
return; return;
if (ip->i_diskflags & GFS2_DIF_SYSTEM) if (ip->i_diskflags & GFS2_DIF_SYSTEM)
return; return;
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) { for (x = 0; x < ip->i_qadata->qa_qd_num; x++) {
qd = ip->i_res->rs_qa_qd[x]; qd = ip->i_qadata->qa_qd[x];
if (qid_eq(qd->qd_id, make_kqid_uid(uid)) || if (qid_eq(qd->qd_id, make_kqid_uid(uid)) ||
qid_eq(qd->qd_id, make_kqid_gid(gid))) { qid_eq(qd->qd_id, make_kqid_gid(gid))) {
...@@ -1635,7 +1670,7 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid, ...@@ -1635,7 +1670,7 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
if (error) if (error)
return error; return error;
error = gfs2_rs_alloc(ip); error = gfs2_rsqa_alloc(ip);
if (error) if (error)
goto out_put; goto out_put;
......
...@@ -18,6 +18,8 @@ struct gfs2_sbd; ...@@ -18,6 +18,8 @@ struct gfs2_sbd;
#define NO_UID_QUOTA_CHANGE INVALID_UID #define NO_UID_QUOTA_CHANGE INVALID_UID
#define NO_GID_QUOTA_CHANGE INVALID_GID #define NO_GID_QUOTA_CHANGE INVALID_GID
extern int gfs2_qa_alloc(struct gfs2_inode *ip);
extern void gfs2_qa_delete(struct gfs2_inode *ip, atomic_t *wcount);
extern int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); extern int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);
extern void gfs2_quota_unhold(struct gfs2_inode *ip); extern void gfs2_quota_unhold(struct gfs2_inode *ip);
......
...@@ -596,27 +596,13 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd) ...@@ -596,27 +596,13 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd)
} }
/** /**
* gfs2_rs_alloc - make sure we have a reservation assigned to the inode * gfs2_rsqa_alloc - make sure we have a reservation assigned to the inode
* plus a quota allocations data structure, if necessary
* @ip: the inode for this reservation * @ip: the inode for this reservation
*/ */
int gfs2_rs_alloc(struct gfs2_inode *ip) int gfs2_rsqa_alloc(struct gfs2_inode *ip)
{ {
int error = 0; return gfs2_qa_alloc(ip);
down_write(&ip->i_rw_mutex);
if (ip->i_res)
goto out;
ip->i_res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
if (!ip->i_res) {
error = -ENOMEM;
goto out;
}
RB_CLEAR_NODE(&ip->i_res->rs_node);
out:
up_write(&ip->i_rw_mutex);
return error;
} }
static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs) static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
...@@ -678,21 +664,20 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs) ...@@ -678,21 +664,20 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
} }
/** /**
* gfs2_rs_delete - delete a multi-block reservation * gfs2_rsqa_delete - delete a multi-block reservation and quota allocation
* @ip: The inode for this reservation * @ip: The inode for this reservation
* @wcount: The inode's write count, or NULL * @wcount: The inode's write count, or NULL
* *
*/ */
void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount) void gfs2_rsqa_delete(struct gfs2_inode *ip, atomic_t *wcount)
{ {
down_write(&ip->i_rw_mutex); down_write(&ip->i_rw_mutex);
if (ip->i_res && ((wcount == NULL) || (atomic_read(wcount) <= 1))) { if ((wcount == NULL) || (atomic_read(wcount) <= 1)) {
gfs2_rs_deltree(ip->i_res); gfs2_rs_deltree(&ip->i_res);
BUG_ON(ip->i_res->rs_free); BUG_ON(ip->i_res.rs_free);
kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
ip->i_res = NULL;
} }
up_write(&ip->i_rw_mutex); up_write(&ip->i_rw_mutex);
gfs2_qa_delete(ip, wcount);
} }
/** /**
...@@ -1158,7 +1143,7 @@ static int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) ...@@ -1158,7 +1143,7 @@ static int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
for (x = 0; x < length; x++) { for (x = 0; x < length; x++) {
bi = rgd->rd_bits + x; bi = rgd->rd_bits + x;
error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh); error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, 0, &bi->bi_bh);
if (error) if (error)
goto fail; goto fail;
} }
...@@ -1456,7 +1441,7 @@ static void rs_insert(struct gfs2_inode *ip) ...@@ -1456,7 +1441,7 @@ static void rs_insert(struct gfs2_inode *ip)
{ {
struct rb_node **newn, *parent = NULL; struct rb_node **newn, *parent = NULL;
int rc; int rc;
struct gfs2_blkreserv *rs = ip->i_res; struct gfs2_blkreserv *rs = &ip->i_res;
struct gfs2_rgrpd *rgd = rs->rs_rbm.rgd; struct gfs2_rgrpd *rgd = rs->rs_rbm.rgd;
u64 fsblock = gfs2_rbm_to_block(&rs->rs_rbm); u64 fsblock = gfs2_rbm_to_block(&rs->rs_rbm);
...@@ -1503,7 +1488,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip, ...@@ -1503,7 +1488,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip,
{ {
struct gfs2_rbm rbm = { .rgd = rgd, }; struct gfs2_rbm rbm = { .rgd = rgd, };
u64 goal; u64 goal;
struct gfs2_blkreserv *rs = ip->i_res; struct gfs2_blkreserv *rs = &ip->i_res;
u32 extlen; u32 extlen;
u32 free_blocks = rgd->rd_free_clone - rgd->rd_reserved; u32 free_blocks = rgd->rd_free_clone - rgd->rd_reserved;
int ret; int ret;
...@@ -1574,7 +1559,7 @@ static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd *rgd, u64 block, ...@@ -1574,7 +1559,7 @@ static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd *rgd, u64 block,
} }
if (n) { if (n) {
while ((rs_cmp(block, length, rs) == 0) && (ip->i_res != rs)) { while ((rs_cmp(block, length, rs) == 0) && (&ip->i_res != rs)) {
block = gfs2_rbm_to_block(&rs->rs_rbm) + rs->rs_free; block = gfs2_rbm_to_block(&rs->rs_rbm) + rs->rs_free;
n = n->rb_right; n = n->rb_right;
if (n == NULL) if (n == NULL)
...@@ -1804,7 +1789,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip ...@@ -1804,7 +1789,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
continue; continue;
*last_unlinked = block; *last_unlinked = block;
error = gfs2_glock_get(sdp, block, &gfs2_inode_glops, CREATE, &gl); error = gfs2_glock_get(sdp, block, &gfs2_iopen_glops, CREATE, &gl);
if (error) if (error)
continue; continue;
...@@ -1984,7 +1969,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) ...@@ -1984,7 +1969,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *begin = NULL; struct gfs2_rgrpd *begin = NULL;
struct gfs2_blkreserv *rs = ip->i_res; struct gfs2_blkreserv *rs = &ip->i_res;
int error = 0, rg_locked, flags = 0; int error = 0, rg_locked, flags = 0;
u64 last_unlinked = NO_BLOCK; u64 last_unlinked = NO_BLOCK;
int loops = 0; int loops = 0;
...@@ -2113,7 +2098,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) ...@@ -2113,7 +2098,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
void gfs2_inplace_release(struct gfs2_inode *ip) void gfs2_inplace_release(struct gfs2_inode *ip)
{ {
struct gfs2_blkreserv *rs = ip->i_res; struct gfs2_blkreserv *rs = &ip->i_res;
if (rs->rs_rgd_gh.gh_gl) if (rs->rs_rgd_gh.gh_gl)
gfs2_glock_dq_uninit(&rs->rs_rgd_gh); gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
...@@ -2267,7 +2252,7 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) ...@@ -2267,7 +2252,7 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd)
static void gfs2_adjust_reservation(struct gfs2_inode *ip, static void gfs2_adjust_reservation(struct gfs2_inode *ip,
const struct gfs2_rbm *rbm, unsigned len) const struct gfs2_rbm *rbm, unsigned len)
{ {
struct gfs2_blkreserv *rs = ip->i_res; struct gfs2_blkreserv *rs = &ip->i_res;
struct gfs2_rgrpd *rgd = rbm->rgd; struct gfs2_rgrpd *rgd = rbm->rgd;
unsigned rlen; unsigned rlen;
u64 block; u64 block;
...@@ -2310,8 +2295,8 @@ static void gfs2_set_alloc_start(struct gfs2_rbm *rbm, ...@@ -2310,8 +2295,8 @@ static void gfs2_set_alloc_start(struct gfs2_rbm *rbm,
{ {
u64 goal; u64 goal;
if (gfs2_rs_active(ip->i_res)) { if (gfs2_rs_active(&ip->i_res)) {
*rbm = ip->i_res->rs_rbm; *rbm = ip->i_res.rs_rbm;
return; return;
} }
...@@ -2365,7 +2350,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, ...@@ -2365,7 +2350,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
gfs2_alloc_extent(&rbm, dinode, nblocks); gfs2_alloc_extent(&rbm, dinode, nblocks);
block = gfs2_rbm_to_block(&rbm); block = gfs2_rbm_to_block(&rbm);
rbm.rgd->rd_last_alloc = block - rbm.rgd->rd_data0; rbm.rgd->rd_last_alloc = block - rbm.rgd->rd_data0;
if (gfs2_rs_active(ip->i_res)) if (gfs2_rs_active(&ip->i_res))
gfs2_adjust_reservation(ip, &rbm, *nblocks); gfs2_adjust_reservation(ip, &rbm, *nblocks);
ndata = *nblocks; ndata = *nblocks;
if (dinode) if (dinode)
......
...@@ -49,9 +49,9 @@ extern void gfs2_inplace_release(struct gfs2_inode *ip); ...@@ -49,9 +49,9 @@ extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
bool dinode, u64 *generation); bool dinode, u64 *generation);
extern int gfs2_rs_alloc(struct gfs2_inode *ip); extern int gfs2_rsqa_alloc(struct gfs2_inode *ip);
extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs); extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs);
extern void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount); extern void gfs2_rsqa_delete(struct gfs2_inode *ip, atomic_t *wcount);
extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta); extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta);
extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
...@@ -78,7 +78,7 @@ extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, ...@@ -78,7 +78,7 @@ extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
extern int gfs2_fitrim(struct file *filp, void __user *argp); extern int gfs2_fitrim(struct file *filp, void __user *argp);
/* This is how to tell if a reservation is in the rgrp tree: */ /* This is how to tell if a reservation is in the rgrp tree: */
static inline bool gfs2_rs_active(struct gfs2_blkreserv *rs) static inline bool gfs2_rs_active(const struct gfs2_blkreserv *rs)
{ {
return rs && !RB_EMPTY_NODE(&rs->rs_node); return rs && !RB_EMPTY_NODE(&rs->rs_node);
} }
......
...@@ -83,6 +83,8 @@ enum { ...@@ -83,6 +83,8 @@ enum {
Opt_nobarrier, Opt_nobarrier,
Opt_rgrplvb, Opt_rgrplvb,
Opt_norgrplvb, Opt_norgrplvb,
Opt_loccookie,
Opt_noloccookie,
Opt_error, Opt_error,
}; };
...@@ -122,6 +124,8 @@ static const match_table_t tokens = { ...@@ -122,6 +124,8 @@ static const match_table_t tokens = {
{Opt_nobarrier, "nobarrier"}, {Opt_nobarrier, "nobarrier"},
{Opt_rgrplvb, "rgrplvb"}, {Opt_rgrplvb, "rgrplvb"},
{Opt_norgrplvb, "norgrplvb"}, {Opt_norgrplvb, "norgrplvb"},
{Opt_loccookie, "loccookie"},
{Opt_noloccookie, "noloccookie"},
{Opt_error, NULL} {Opt_error, NULL}
}; };
...@@ -278,6 +282,12 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) ...@@ -278,6 +282,12 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
case Opt_norgrplvb: case Opt_norgrplvb:
args->ar_rgrplvb = 0; args->ar_rgrplvb = 0;
break; break;
case Opt_loccookie:
args->ar_loccookie = 1;
break;
case Opt_noloccookie:
args->ar_loccookie = 0;
break;
case Opt_error: case Opt_error:
default: default:
pr_warn("invalid mount option: %s\n", o); pr_warn("invalid mount option: %s\n", o);
...@@ -556,6 +566,7 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, ...@@ -556,6 +566,7 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
gfs2_trans_add_meta(l_ip->i_gl, l_bh); gfs2_trans_add_meta(l_ip->i_gl, l_bh);
gfs2_trans_add_meta(m_ip->i_gl, m_bh);
spin_lock(&sdp->sd_statfs_spin); spin_lock(&sdp->sd_statfs_spin);
m_sc->sc_total += l_sc->sc_total; m_sc->sc_total += l_sc->sc_total;
...@@ -564,10 +575,8 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, ...@@ -564,10 +575,8 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
memset(l_bh->b_data + sizeof(struct gfs2_dinode), memset(l_bh->b_data + sizeof(struct gfs2_dinode),
0, sizeof(struct gfs2_statfs_change)); 0, sizeof(struct gfs2_statfs_change));
spin_unlock(&sdp->sd_statfs_spin);
gfs2_trans_add_meta(m_ip->i_gl, m_bh);
gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
spin_unlock(&sdp->sd_statfs_spin);
} }
int gfs2_statfs_sync(struct super_block *sb, int type) int gfs2_statfs_sync(struct super_block *sb, int type)
...@@ -842,10 +851,6 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) ...@@ -842,10 +851,6 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
gfs2_quota_sync(sdp->sd_vfs, 0); gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_statfs_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0);
down_write(&sdp->sd_log_flush_lock);
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
up_write(&sdp->sd_log_flush_lock);
gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH); gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH);
wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0); wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0);
gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks); gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
...@@ -1419,6 +1424,8 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root) ...@@ -1419,6 +1424,8 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",demote_interface_used"); seq_puts(s, ",demote_interface_used");
if (args->ar_rgrplvb) if (args->ar_rgrplvb)
seq_puts(s, ",rgrplvb"); seq_puts(s, ",rgrplvb");
if (args->ar_loccookie)
seq_puts(s, ",loccookie");
return 0; return 0;
} }
...@@ -1512,6 +1519,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1512,6 +1519,7 @@ static void gfs2_evict_inode(struct inode *inode)
struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh; struct gfs2_holder gh;
struct address_space *metamapping;
int error; int error;
if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) { if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) {
...@@ -1526,7 +1534,8 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1526,7 +1534,8 @@ static void gfs2_evict_inode(struct inode *inode)
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh);
if (unlikely(error)) { if (unlikely(error)) {
ip->i_iopen_gh.gh_flags |= GL_NOCACHE; ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_dq_wait(&ip->i_iopen_gh);
gfs2_holder_uninit(&ip->i_iopen_gh);
goto out; goto out;
} }
...@@ -1575,8 +1584,8 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1575,8 +1584,8 @@ static void gfs2_evict_inode(struct inode *inode)
out_truncate: out_truncate:
gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
metamapping = gfs2_glock2aspace(ip->i_gl);
if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) { if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) {
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
filemap_fdatawrite(metamapping); filemap_fdatawrite(metamapping);
filemap_fdatawait(metamapping); filemap_fdatawait(metamapping);
} }
...@@ -1589,16 +1598,17 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1589,16 +1598,17 @@ static void gfs2_evict_inode(struct inode *inode)
goto out_unlock; goto out_unlock;
/* Needs to be done before glock release & also in a transaction */ /* Needs to be done before glock release & also in a transaction */
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
truncate_inode_pages(metamapping, 0);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_unlock: out_unlock:
/* Error path for case 1 */ /* Error path for case 1 */
if (gfs2_rs_active(ip->i_res)) if (gfs2_rs_active(&ip->i_res))
gfs2_rs_deltree(ip->i_res); gfs2_rs_deltree(&ip->i_res);
if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) {
ip->i_iopen_gh.gh_flags |= GL_NOCACHE; ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq(&ip->i_iopen_gh); gfs2_glock_dq_wait(&ip->i_iopen_gh);
} }
gfs2_holder_uninit(&ip->i_iopen_gh); gfs2_holder_uninit(&ip->i_iopen_gh);
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
...@@ -1607,7 +1617,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1607,7 +1617,7 @@ static void gfs2_evict_inode(struct inode *inode)
out: out:
/* Case 3 starts here */ /* Case 3 starts here */
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);
gfs2_rs_delete(ip, NULL); gfs2_rsqa_delete(ip, NULL);
gfs2_ordered_del_inode(ip); gfs2_ordered_del_inode(ip);
clear_inode(inode); clear_inode(inode);
gfs2_dir_hash_inval(ip); gfs2_dir_hash_inval(ip);
...@@ -1619,7 +1629,8 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1619,7 +1629,8 @@ static void gfs2_evict_inode(struct inode *inode)
if (ip->i_iopen_gh.gh_gl) { if (ip->i_iopen_gh.gh_gl) {
ip->i_iopen_gh.gh_gl->gl_object = NULL; ip->i_iopen_gh.gh_gl->gl_object = NULL;
ip->i_iopen_gh.gh_flags |= GL_NOCACHE; ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_dq_wait(&ip->i_iopen_gh);
gfs2_holder_uninit(&ip->i_iopen_gh);
} }
} }
...@@ -1632,7 +1643,9 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) ...@@ -1632,7 +1643,9 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
ip->i_flags = 0; ip->i_flags = 0;
ip->i_gl = NULL; ip->i_gl = NULL;
ip->i_rgd = NULL; ip->i_rgd = NULL;
ip->i_res = NULL; memset(&ip->i_res, 0, sizeof(ip->i_res));
RB_CLEAR_NODE(&ip->i_res.rs_node);
ip->i_rahead = 0;
} }
return &ip->i_inode; return &ip->i_inode;
} }
......
...@@ -27,7 +27,7 @@ struct kmem_cache *gfs2_inode_cachep __read_mostly; ...@@ -27,7 +27,7 @@ struct kmem_cache *gfs2_inode_cachep __read_mostly;
struct kmem_cache *gfs2_bufdata_cachep __read_mostly; struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
struct kmem_cache *gfs2_rgrpd_cachep __read_mostly; struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
struct kmem_cache *gfs2_quotad_cachep __read_mostly; struct kmem_cache *gfs2_quotad_cachep __read_mostly;
struct kmem_cache *gfs2_rsrv_cachep __read_mostly; struct kmem_cache *gfs2_qadata_cachep __read_mostly;
mempool_t *gfs2_page_pool __read_mostly; mempool_t *gfs2_page_pool __read_mostly;
void gfs2_assert_i(struct gfs2_sbd *sdp) void gfs2_assert_i(struct gfs2_sbd *sdp)
......
...@@ -149,7 +149,7 @@ extern struct kmem_cache *gfs2_inode_cachep; ...@@ -149,7 +149,7 @@ extern struct kmem_cache *gfs2_inode_cachep;
extern struct kmem_cache *gfs2_bufdata_cachep; extern struct kmem_cache *gfs2_bufdata_cachep;
extern struct kmem_cache *gfs2_rgrpd_cachep; extern struct kmem_cache *gfs2_rgrpd_cachep;
extern struct kmem_cache *gfs2_quotad_cachep; extern struct kmem_cache *gfs2_quotad_cachep;
extern struct kmem_cache *gfs2_rsrv_cachep; extern struct kmem_cache *gfs2_qadata_cachep;
extern mempool_t *gfs2_page_pool; extern mempool_t *gfs2_page_pool;
static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
......
...@@ -119,7 +119,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) ...@@ -119,7 +119,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
__be64 *eablk, *end; __be64 *eablk, *end;
int error; int error;
error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, &bh); error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, 0, &bh);
if (error) if (error)
return error; return error;
...@@ -143,7 +143,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data) ...@@ -143,7 +143,7 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
break; break;
bn = be64_to_cpu(*eablk); bn = be64_to_cpu(*eablk);
error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh); error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, 0, &eabh);
if (error) if (error)
break; break;
error = ea_foreach_i(ip, eabh, ea_call, data); error = ea_foreach_i(ip, eabh, ea_call, data);
...@@ -477,7 +477,7 @@ static int gfs2_iter_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, ...@@ -477,7 +477,7 @@ static int gfs2_iter_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
return -ENOMEM; return -ENOMEM;
for (x = 0; x < nptrs; x++) { for (x = 0; x < nptrs; x++) {
error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, 0,
bh + x); bh + x);
if (error) { if (error) {
while (x--) while (x--)
...@@ -979,7 +979,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -979,7 +979,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) { if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) {
__be64 *end; __be64 *end;
error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, 0,
&indbh); &indbh);
if (error) if (error)
return error; return error;
...@@ -1256,7 +1256,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) ...@@ -1256,7 +1256,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, &indbh); error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, 0, &indbh);
if (error) if (error)
return error; return error;
......
...@@ -297,6 +297,8 @@ struct gfs2_dinode { ...@@ -297,6 +297,8 @@ struct gfs2_dinode {
#define GFS2_FNAMESIZE 255 #define GFS2_FNAMESIZE 255
#define GFS2_DIRENT_SIZE(name_len) ((sizeof(struct gfs2_dirent) + (name_len) + 7) & ~7) #define GFS2_DIRENT_SIZE(name_len) ((sizeof(struct gfs2_dirent) + (name_len) + 7) & ~7)
#define GFS2_MIN_DIRENT_SIZE (GFS2_DIRENT_SIZE(1))
struct gfs2_dirent { struct gfs2_dirent {
struct gfs2_inum de_inum; struct gfs2_inum de_inum;
...@@ -304,11 +306,12 @@ struct gfs2_dirent { ...@@ -304,11 +306,12 @@ struct gfs2_dirent {
__be16 de_rec_len; __be16 de_rec_len;
__be16 de_name_len; __be16 de_name_len;
__be16 de_type; __be16 de_type;
__be16 de_rahead;
union { union {
__u8 __pad[14]; __u8 __pad[12];
struct { struct {
__be16 de_rahead; __u32 de_cookie; /* ondisk value not used */
__u8 pad2[12]; __u8 pad3[8];
}; };
}; };
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册