Commit 4d589677 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 33caf82a a93a9983
...@@ -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);