X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fgfs2%2Fdir.c;h=b7c8e5c70791b232f744bc047b3a6169634ffa07;hb=3c289ba7c320560ee74979a8895141c829046a2d;hp=59d0cbcaecffc1abed7fe64d154d3e0b07f57453;hpb=a91ea69ffd3f8a0b7139bfd44042ab384461e631;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 59d0cbc..b7c8e5c 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -36,7 +36,7 @@ * the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the * beginning of the leaf block. The dirents reside in leaves when * - * dip->i_di.di_flags & GFS2_DIF_EXHASH is true + * dip->i_diskflags & GFS2_DIF_EXHASH is true * * Otherwise, the dirents are "linear", within a single stuffed dinode block. * @@ -53,7 +53,6 @@ * but never before the maximum hash table size has been reached. */ -#include #include #include #include @@ -61,9 +60,9 @@ #include #include #include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "dir.h" #include "glock.h" @@ -78,15 +77,16 @@ #define IS_LEAF 1 /* Hashed (leaf) directory */ #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ -#define gfs2_disk_hash2offset(h) (((uint64_t)(h)) >> 1) -#define gfs2_dir_offset2hash(p) ((uint32_t)(((uint64_t)(p)) << 1)) +#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1) +#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1)) -typedef int (*leaf_call_t) (struct gfs2_inode *dip, - uint32_t index, uint32_t len, uint64_t leaf_no, - void *data); +typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len, + u64 leaf_no, void *data); +typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, + const struct qstr *name, void *opaque); -int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, +int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) { struct buffer_head *bh; @@ -99,13 +99,13 @@ int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block, return 0; } -static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, uint64_t block, +static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) { struct buffer_head *bh; int error; - error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT, &bh); + error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh); if (error) return error; if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) { @@ -118,7 +118,6 @@ static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, uint64_t block, static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, unsigned int offset, unsigned int size) - { struct buffer_head *dibh; int error; @@ -129,10 +128,10 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, gfs2_trans_add_bh(ip->i_gl, dibh, 1); memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size); - if (ip->i_di.di_size < offset + size) - ip->i_di.di_size = offset + size; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + if (ip->i_disksize < offset + size) + ip->i_disksize = offset + size; + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -151,15 +150,16 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, * Returns: The number of bytes correctly written or error code */ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, - uint64_t offset, unsigned int size) + u64 offset, unsigned int size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *dibh; - uint64_t lblock, dblock; - uint32_t extlen = 0; + u64 lblock, dblock; + u32 extlen = 0; unsigned int o; int copied = 0; int error = 0; + int new = 0; if (!size) return 0; @@ -184,7 +184,6 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, while (copied < size) { unsigned int amount; struct buffer_head *bh; - int new; amount = size - copied; if (amount > sdp->sd_sb.sb_bsize - o) @@ -212,8 +211,6 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, gfs2_trans_add_bh(ip->i_gl, bh, 1); memcpy(bh->b_data + o, buf, amount); brelse(bh); - if (error) - goto fail; buf += amount; copied += amount; @@ -229,12 +226,12 @@ out: if (error) return error; - if (ip->i_di.di_size < offset + copied) - ip->i_di.di_size = offset + copied; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + if (ip->i_disksize < offset + copied) + ip->i_disksize = offset + copied; + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); return copied; @@ -245,7 +242,7 @@ fail: } static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, - unsigned int offset, unsigned int size) + u64 offset, unsigned int size) { struct buffer_head *dibh; int error; @@ -270,28 +267,27 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, * * Returns: The amount of data actually copied or the error */ -static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, - uint64_t offset, unsigned int size) +static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, + unsigned int size, unsigned ra) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - uint64_t lblock, dblock; - uint32_t extlen = 0; + u64 lblock, dblock; + u32 extlen = 0; unsigned int o; int copied = 0; int error = 0; - if (offset >= ip->i_di.di_size) + if (offset >= ip->i_disksize) return 0; - if ((offset + size) > ip->i_di.di_size) - size = ip->i_di.di_size - offset; + if (offset + size > ip->i_disksize) + size = ip->i_disksize - offset; if (!size) return 0; if (gfs2_is_stuffed(ip)) - return gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset, - size); + return gfs2_dir_read_stuffed(ip, buf, offset, size); if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip))) return -EINVAL; @@ -312,34 +308,29 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, new = 0; error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); - if (error) + if (error || !dblock) goto fail; - } - - if (extlen > 1) - gfs2_meta_ra(ip->i_gl, dblock, extlen); - - if (dblock) { - if (new) - error = gfs2_dir_get_new_buffer(ip, dblock, &bh); - else - error = gfs2_dir_get_existing_buffer(ip, dblock, &bh); + BUG_ON(extlen < 1); + if (!ra) + extlen = 1; + bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); + } else { + error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); if (error) goto fail; - dblock++; - extlen--; - } else - bh = NULL; - + } + error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD); + if (error) { + brelse(bh); + goto fail; + } + dblock++; + extlen--; memcpy(buf, bh->b_data + o, amount); brelse(bh); - if (error) - goto fail; - buf += amount; copied += amount; lblock++; - o = sizeof(struct gfs2_meta_header); } @@ -348,17 +339,18 @@ fail: return (copied) ? copied : error; } -typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, - const struct qstr *name, - void *opaque); +static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent) +{ + return dent->de_inum.no_addr == 0 || dent->de_inum.no_formal_ino == 0; +} static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, const struct qstr *name, int ret) { - if (dent->de_inum.no_addr != 0 && + if (!gfs2_dirent_sentinel(dent) && be32_to_cpu(dent->de_hash) == name->hash && be16_to_cpu(dent->de_name_len) == name->len && - memcmp((char *)(dent+1), name->name, name->len) == 0) + memcmp(dent+1, name->name, name->len) == 0) return ret; return 0; } @@ -400,9 +392,9 @@ static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); unsigned totlen = be16_to_cpu(dent->de_rec_len); - if (!dent->de_inum.no_addr) + if (gfs2_dirent_sentinel(dent)) actual = GFS2_DIRENT_SIZE(0); - if ((totlen - actual) >= required) + if (totlen - actual >= required) return 1; return 0; } @@ -417,7 +409,7 @@ static int gfs2_dirent_gather(const struct gfs2_dirent *dent, void *opaque) { struct dirent_gather *g = opaque; - if (dent->de_inum.no_addr) { + if (!gfs2_dirent_sentinel(dent)) { g->pdent[g->offset++] = dent; } return 0; @@ -445,10 +437,10 @@ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, if (unlikely(offset + size > len)) goto error; msg = "zero inode number"; - if (unlikely(!first && !dent->de_inum.no_addr)) + if (unlikely(!first && gfs2_dirent_sentinel(dent))) goto error; msg = "name length is greater than space in dirent"; - if (dent->de_inum.no_addr && + if (!gfs2_dirent_sentinel(dent) && unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) > size)) goto error; @@ -483,8 +475,7 @@ wrong_type: return -1; } -static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, - void *buf, +static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, unsigned int len, gfs2_dscan_t scan, const struct qstr *name, void *opaque) @@ -500,7 +491,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, offset = ret; prev = NULL; - dent = (struct gfs2_dirent *)(buf + offset); + dent = buf + offset; size = be16_to_cpu(dent->de_rec_len); if (gfs2_check_dirent(dent, offset, size, len, 1)) goto consist_inode; @@ -512,7 +503,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, if (offset == len) break; prev = dent; - dent = (struct gfs2_dirent *)(buf + offset); + dent = buf + offset; size = be16_to_cpu(dent->de_rec_len); if (gfs2_check_dirent(dent, offset, size, len, 0)) goto consist_inode; @@ -567,6 +558,24 @@ static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, } } +static int dirent_check_reclen(struct gfs2_inode *dip, + const struct gfs2_dirent *d, const void *end_p) +{ + const void *ptr = d; + u16 rec_len = be16_to_cpu(d->de_rec_len); + + if (unlikely(rec_len < sizeof(struct gfs2_dirent))) + goto broken; + ptr += rec_len; + if (ptr < end_p) + return rec_len; + if (ptr == end_p) + return -ENOENT; +broken: + gfs2_consist_inode(dip); + return -EIO; +} + /** * dirent_next - Next dirent * @dip: the directory @@ -579,42 +588,26 @@ static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent **dent) { - struct gfs2_dirent *tmp, *cur; - char *bh_end; - uint16_t cur_rec_len; - - cur = *dent; - bh_end = bh->b_data + bh->b_size; - cur_rec_len = be16_to_cpu(cur->de_rec_len); - - if ((char *)cur + cur_rec_len >= bh_end) { - if ((char *)cur + cur_rec_len > bh_end) { - gfs2_consist_inode(dip); - return -EIO; - } - return -ENOENT; - } - - tmp = (struct gfs2_dirent *)((char *)cur + cur_rec_len); + struct gfs2_dirent *cur = *dent, *tmp; + char *bh_end = bh->b_data + bh->b_size; + int ret; - if ((char *)tmp + be16_to_cpu(tmp->de_rec_len) > bh_end) { - gfs2_consist_inode(dip); - return -EIO; - } + ret = dirent_check_reclen(dip, cur, bh_end); + if (ret < 0) + return ret; - if (cur_rec_len == 0) { - gfs2_consist_inode(dip); - return -EIO; - } + tmp = (void *)cur + ret; + ret = dirent_check_reclen(dip, tmp, bh_end); + if (ret == -EIO) + return ret; /* Only the first dent could ever have de_inum.no_addr == 0 */ - if (!tmp->de_inum.no_addr) { + if (gfs2_dirent_sentinel(tmp)) { gfs2_consist_inode(dip); return -EIO; } *dent = tmp; - return 0; } @@ -630,9 +623,9 @@ static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh, static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, struct gfs2_dirent *prev, struct gfs2_dirent *cur) { - uint16_t cur_rec_len, prev_rec_len; + u16 cur_rec_len, prev_rec_len; - if (!cur->de_inum.no_addr) { + if (gfs2_dirent_sentinel(cur)) { gfs2_consist_inode(dip); return; } @@ -644,7 +637,8 @@ static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh, out the inode number and return. */ if (!prev) { - cur->de_inum.no_addr = 0; /* No endianess worries */ + cur->de_inum.no_addr = 0; + cur->de_inum.no_formal_ino = 0; return; } @@ -675,7 +669,7 @@ static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode, struct gfs2_dirent *ndent; unsigned offset = 0, totlen; - if (dent->de_inum.no_addr) + if (!gfs2_dirent_sentinel(dent)) offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); totlen = be16_to_cpu(dent->de_rec_len); BUG_ON(offset + name->len > totlen); @@ -691,19 +685,19 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, const struct qstr *name) { 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); if (!dent || IS_ERR(dent)) return dent; return gfs2_init_dirent(inode, dent, name, bh); } -static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, +static int get_leaf(struct gfs2_inode *dip, u64 leaf_no, struct buffer_head **bhp) { int error; - error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp); + error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp); if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) { /* printk(KERN_INFO "block num=%llu\n", leaf_no); */ error = -EIO; @@ -721,16 +715,16 @@ static int get_leaf(struct gfs2_inode *dip, uint64_t leaf_no, * Returns: 0 on success, error code otherwise */ -static int get_leaf_nr(struct gfs2_inode *dip, uint32_t index, - uint64_t *leaf_out) +static int get_leaf_nr(struct gfs2_inode *dip, u32 index, + u64 *leaf_out) { - uint64_t leaf_no; + __be64 leaf_no; int error; error = gfs2_dir_read_data(dip, (char *)&leaf_no, - index * sizeof(uint64_t), - sizeof(uint64_t)); - if (error != sizeof(uint64_t)) + index * sizeof(__be64), + sizeof(__be64), 0); + if (error != sizeof(u64)) return (error < 0) ? error : -EIO; *leaf_out = be64_to_cpu(leaf_no); @@ -738,10 +732,10 @@ static int get_leaf_nr(struct gfs2_inode *dip, uint32_t index, return 0; } -static int get_first_leaf(struct gfs2_inode *dip, uint32_t index, +static int get_first_leaf(struct gfs2_inode *dip, u32 index, struct buffer_head **bh_out) { - uint64_t leaf_no; + u64 leaf_no; int error; error = get_leaf_nr(dip, index, &leaf_no); @@ -761,17 +755,17 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, struct gfs2_inode *ip = GFS2_I(inode); int error; - if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { + if (ip->i_diskflags & GFS2_DIF_EXHASH) { struct gfs2_leaf *leaf; - unsigned hsize = 1 << ip->i_di.di_depth; + unsigned hsize = 1 << ip->i_depth; unsigned index; u64 ln; - if (hsize * sizeof(u64) != ip->i_di.di_size) { + if (hsize * sizeof(u64) != ip->i_disksize) { gfs2_consist_inode(ip); return ERR_PTR(-EIO); } - - index = name->hash >> (32 - ip->i_di.di_depth); + + index = name->hash >> (32 - ip->i_depth); error = get_first_leaf(ip, index, &bh); if (error) return ERR_PTR(error); @@ -785,14 +779,14 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, brelse(bh); if (!ln) break; - + error = get_leaf(ip, ln, &bh); } while(!error); return error ? ERR_PTR(error) : NULL; } - + error = gfs2_meta_inode_buffer(ip, &bh); if (error) return ERR_PTR(error); @@ -809,21 +803,22 @@ got_dent: static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) { struct gfs2_inode *ip = GFS2_I(inode); - u64 bn = gfs2_alloc_meta(ip); + unsigned int n = 1; + u64 bn = gfs2_alloc_block(ip, &n); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct gfs2_leaf *leaf; struct gfs2_dirent *dent; struct qstr name = { .name = "", .len = 0, .hash = 0 }; if (!bh) return NULL; - + gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); leaf = (struct gfs2_leaf *)bh->b_data; leaf->lf_depth = cpu_to_be16(depth); - leaf->lf_entries = cpu_to_be16(0); - leaf->lf_dirent_format = cpu_to_be16(GFS2_FORMAT_DE); - leaf->lf_next = cpu_to_be64(0); + leaf->lf_entries = 0; + leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); + leaf->lf_next = 0; memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); dent = (struct gfs2_dirent *)(leaf+1); gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); @@ -847,8 +842,9 @@ static int dir_make_exhash(struct inode *inode) struct buffer_head *bh, *dibh; struct gfs2_leaf *leaf; int y; - uint32_t x; - uint64_t *lp, bn; + u32 x; + __be64 *lp; + u64 bn; int error; error = gfs2_meta_inode_buffer(dip, &dibh); @@ -862,8 +858,8 @@ static int dir_make_exhash(struct inode *inode) return -ENOSPC; bn = bh->b_blocknr; - gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16)); - leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries); + gfs2_assert(sdp, dip->i_entries < (1 << 16)); + leaf->lf_entries = cpu_to_be16(dip->i_entries); /* Copy dirents */ @@ -904,20 +900,19 @@ static int dir_make_exhash(struct inode *inode) gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - lp = (uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode)); + lp = (__be64 *)(dibh->b_data + sizeof(struct gfs2_dinode)); for (x = sdp->sd_hash_ptrs; x--; lp++) *lp = cpu_to_be64(bn); - dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; - dip->i_di.di_blocks++; - dip->i_di.di_flags |= GFS2_DIF_EXHASH; - dip->i_di.di_payload_format = 0; + dip->i_disksize = sdp->sd_sb.sb_bsize / 2; + gfs2_add_inode_blocks(&dip->i_inode, 1); + dip->i_diskflags |= GFS2_DIF_EXHASH; for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; - dip->i_di.di_depth = y; + dip->i_depth = y; - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); @@ -939,13 +934,14 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) struct buffer_head *nbh, *obh, *dibh; struct gfs2_leaf *nleaf, *oleaf; struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new; - uint32_t start, len, half_len, divider; - uint64_t bn, *lp, leaf_no; - uint32_t index; + u32 start, len, half_len, divider; + u64 bn, leaf_no; + __be64 *lp; + u32 index; int x, moved = 0; int error; - index = name->hash >> (32 - dip->i_di.di_depth); + index = name->hash >> (32 - dip->i_depth); error = get_leaf_nr(dip, index, &leaf_no); if (error) return error; @@ -956,7 +952,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) return error; oleaf = (struct gfs2_leaf *)obh->b_data; - if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) { + if (dip->i_depth == be16_to_cpu(oleaf->lf_depth)) { brelse(obh); return 1; /* can't split */ } @@ -971,10 +967,10 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) bn = nbh->b_blocknr; /* Compute the start and len of leaf pointers in the hash table. */ - len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); + len = 1 << (dip->i_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { - printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index); + printk(KERN_WARNING "i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); gfs2_consist_inode(dip); error = -EIO; goto fail_brelse; @@ -985,14 +981,14 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) /* Change the pointers. Don't bother distinguishing stuffed from non-stuffed. This code is complicated enough already. */ - lp = kmalloc(half_len * sizeof(uint64_t), GFP_NOFS | __GFP_NOFAIL); + lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS | __GFP_NOFAIL); /* Change the pointers */ for (x = 0; x < half_len; x++) lp[x] = cpu_to_be64(bn); - error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), - half_len * sizeof(uint64_t)); - if (error != half_len * sizeof(uint64_t)) { + error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64), + half_len * sizeof(u64)); + if (error != half_len * sizeof(u64)) { if (error >= 0) error = -EIO; goto fail_lpfree; @@ -1001,7 +997,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) kfree(lp); /* Compute the divider */ - divider = (start + half_len) << (32 - dip->i_di.di_depth); + divider = (start + half_len) << (32 - dip->i_depth); /* Copy the entries */ dirent_first(dip, obh, &dent); @@ -1011,7 +1007,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) if (dirent_next(dip, obh, &next)) next = NULL; - if (dent->de_inum.no_addr && + if (!gfs2_dirent_sentinel(dent) && be32_to_cpu(dent->de_hash) < divider) { struct qstr str; str.name = (char*)(dent+1); @@ -1025,13 +1021,13 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) new->de_inum = dent->de_inum; /* No endian worries */ new->de_type = dent->de_type; /* No endian worries */ - nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1); + be16_add_cpu(&nleaf->lf_entries, 1); dirent_del(dip, obh, prev, dent); if (!oleaf->lf_entries) gfs2_consist_inode(dip); - oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1); + be16_add_cpu(&oleaf->lf_entries, -1); if (!prev) prev = dent; @@ -1047,8 +1043,9 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { - dip->i_di.di_blocks++; - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_trans_add_bh(dip->i_gl, dibh, 1); + gfs2_add_inode_blocks(&dip->i_inode, 1); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); } @@ -1077,27 +1074,27 @@ static int dir_double_exhash(struct gfs2_inode *dip) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *dibh; - uint32_t hsize; - uint64_t *buf; - uint64_t *from, *to; - uint64_t block; + u32 hsize; + u64 *buf; + u64 *from, *to; + u64 block; int x; int error = 0; - hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + hsize = 1 << dip->i_depth; + if (hsize * sizeof(u64) != dip->i_disksize) { gfs2_consist_inode(dip); return -EIO; } /* Allocate both the "from" and "to" buffers in one big chunk */ - buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL); + buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS | __GFP_NOFAIL); - for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { + for (block = dip->i_disksize >> sdp->sd_hash_bsize_shift; block--;) { error = gfs2_dir_read_data(dip, (char *)buf, block * sdp->sd_hash_bsize, - sdp->sd_hash_bsize); + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1105,7 +1102,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) } from = buf; - to = (uint64_t *)((char *)buf + sdp->sd_hash_bsize); + to = (u64 *)((char *)buf + sdp->sd_hash_bsize); for (x = sdp->sd_hash_ptrs; x--; from++) { *to++ = *from; /* No endianess worries */ @@ -1127,8 +1124,8 @@ static int dir_double_exhash(struct gfs2_inode *dip) error = gfs2_meta_inode_buffer(dip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { - dip->i_di.di_depth++; - gfs2_dinode_out(&dip->i_di, dibh->b_data); + dip->i_depth++; + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); } @@ -1152,14 +1149,14 @@ fail: static int compare_dents(const void *a, const void *b) { - struct gfs2_dirent *dent_a, *dent_b; - uint32_t hash_a, hash_b; + const struct gfs2_dirent *dent_a, *dent_b; + u32 hash_a, hash_b; int ret = 0; - dent_a = *(struct gfs2_dirent **)a; + dent_a = *(const struct gfs2_dirent **)a; hash_a = be32_to_cpu(dent_a->de_hash); - dent_b = *(struct gfs2_dirent **)b; + dent_b = *(const struct gfs2_dirent **)b; hash_b = be32_to_cpu(dent_b->de_hash); if (hash_a > hash_b) @@ -1175,9 +1172,7 @@ static int compare_dents(const void *a, const void *b) else if (len_a < len_b) ret = -1; else - ret = memcmp((char *)(dent_a + 1), - (char *)(dent_b + 1), - len_a); + ret = memcmp(dent_a + 1, dent_b + 1, len_a); } return ret; @@ -1201,14 +1196,13 @@ static int compare_dents(const void *a, const void *b) * Returns: errno, >0 on exception from filldir */ -static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, - void *opaque, gfs2_filldir_t filldir, - const struct gfs2_dirent **darr, uint32_t entries, +static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, + void *opaque, filldir_t filldir, + const struct gfs2_dirent **darr, u32 entries, int *copied) { const struct gfs2_dirent *dent, *dent_next; - struct gfs2_inum inum; - uint64_t off, off_next; + u64 off, off_next; unsigned int x, y; int run = 0; int error = 0; @@ -1244,11 +1238,9 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, *offset = off; } - gfs2_inum_in(&inum, (char *)&dent->de_inum); - - error = filldir(opaque, (char *)(dent + 1), + error = filldir(opaque, (const char *)(dent + 1), be16_to_cpu(dent->de_name_len), - off, &inum, + off, be64_to_cpu(dent->de_inum.no_addr), be16_to_cpu(dent->de_type)); if (error) return 1; @@ -1266,13 +1258,14 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, } static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, - gfs2_filldir_t filldir, int *copied, - unsigned *depth, u64 leaf_no) + filldir_t filldir, int *copied, unsigned *depth, + u64 leaf_no) { struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *bh; struct gfs2_leaf *lf; - unsigned entries = 0; + unsigned entries = 0, entries2 = 0; unsigned leaves = 0; const struct gfs2_dirent **darr, *dent; struct dirent_gather g; @@ -1298,7 +1291,13 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, return 0; error = -ENOMEM; - larr = vmalloc((leaves + entries) * sizeof(void*)); + /* + * The extra 99 entries are not normally used, but are a buffer + * zone in case the number of entries in the leaf is corrupt. + * 99 is the maximum number of entries that can fit in a single + * leaf block. + */ + larr = vmalloc((leaves + entries + 99) * sizeof(void *)); if (!larr) goto out; darr = (const struct gfs2_dirent **)(larr + leaves); @@ -1313,10 +1312,20 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, lf = (struct gfs2_leaf *)bh->b_data; lfn = be64_to_cpu(lf->lf_next); if (lf->lf_entries) { + entries2 += be16_to_cpu(lf->lf_entries); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_gather, NULL, &g); error = PTR_ERR(dent); - if (IS_ERR(dent)) { + if (IS_ERR(dent)) + goto out_kfree; + if (entries2 != g.offset) { + fs_warn(sdp, "Number of entries corrupt in dir " + "leaf %llu, entries2 (%u) != " + "g.offset (%u)\n", + (unsigned long long)bh->b_blocknr, + entries2, g.offset); + + error = -EIO; goto out_kfree; } error = 0; @@ -1326,6 +1335,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, } } while(lfn); + BUG_ON(entries2 != entries); error = do_filldir_main(ip, offset, opaque, filldir, darr, entries, copied); out_kfree: @@ -1346,29 +1356,29 @@ out: * Returns: errno */ -static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, - gfs2_filldir_t filldir) +static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, + filldir_t filldir) { struct gfs2_inode *dip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - uint32_t hsize, len = 0; - uint32_t ht_offset, lp_offset, ht_offset_cur = -1; - uint32_t hash, index; - uint64_t *lp; + u32 hsize, len = 0; + u32 ht_offset, lp_offset, ht_offset_cur = -1; + u32 hash, index; + __be64 *lp; int copied = 0; int error = 0; unsigned depth = 0; - hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + hsize = 1 << dip->i_depth; + if (hsize * sizeof(u64) != dip->i_disksize) { gfs2_consist_inode(dip); return -EIO; } hash = gfs2_dir_offset2hash(*offset); - index = hash >> (32 - dip->i_di.di_depth); + index = hash >> (32 - dip->i_depth); - lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS); if (!lp) return -ENOMEM; @@ -1378,8 +1388,8 @@ static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, - ht_offset * sizeof(uint64_t), - sdp->sd_hash_bsize); + ht_offset * sizeof(__be64), + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1394,7 +1404,7 @@ static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, if (error) break; - len = 1 << (dip->i_di.di_depth - depth); + len = 1 << (dip->i_depth - depth); index = (index & ~(len - 1)) + len; } @@ -1405,20 +1415,21 @@ out: return error; } -int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque, - gfs2_filldir_t filldir) +int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, + filldir_t filldir) { struct gfs2_inode *dip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); struct dirent_gather g; const struct gfs2_dirent **darr, *dent; struct buffer_head *dibh; int copied = 0; int error; - if (!dip->i_di.di_entries) + if (!dip->i_entries) return 0; - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) + if (dip->i_diskflags & GFS2_DIF_EXHASH) return dir_e_read(inode, offset, opaque, filldir); if (!gfs2_is_stuffed(dip)) { @@ -1431,8 +1442,8 @@ int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque, return error; error = -ENOMEM; - darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *), - GFP_KERNEL); + /* 96 is max number of dirents which can be stuffed into an inode */ + darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_NOFS); if (darr) { g.pdent = darr; g.offset = 0; @@ -1442,8 +1453,17 @@ int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque, error = PTR_ERR(dent); goto out; } + if (dip->i_entries != g.offset) { + fs_warn(sdp, "Number of entries corrupt in dir %llu, " + "ip->i_entries (%u) != g.offset (%u)\n", + (unsigned long long)dip->i_no_addr, + dip->i_entries, + g.offset); + error = -EIO; + goto out; + } error = do_filldir_main(dip, offset, opaque, filldir, darr, - dip->i_di.di_entries, &copied); + dip->i_entries, &copied); out: kfree(darr); } @@ -1468,24 +1488,55 @@ out: * Returns: errno */ -int gfs2_dir_search(struct inode *dir, const struct qstr *name, - struct gfs2_inum *inum, unsigned int *type) +struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) +{ + struct buffer_head *bh; + struct gfs2_dirent *dent; + struct inode *inode; + + dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); + if (dent) { + if (IS_ERR(dent)) + return ERR_CAST(dent); + inode = gfs2_inode_lookup(dir->i_sb, + be16_to_cpu(dent->de_type), + be64_to_cpu(dent->de_inum.no_addr), + be64_to_cpu(dent->de_inum.no_formal_ino), 0); + brelse(bh); + return inode; + } + return ERR_PTR(-ENOENT); +} + +int gfs2_dir_check(struct inode *dir, const struct qstr *name, + const struct gfs2_inode *ip) { struct buffer_head *bh; struct gfs2_dirent *dent; + int ret = -ENOENT; dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); if (dent) { if (IS_ERR(dent)) return PTR_ERR(dent); - if (inum) - gfs2_inum_in(inum, (char *)&dent->de_inum); - if (type) - *type = be16_to_cpu(dent->de_type); + if (ip) { + if (be64_to_cpu(dent->de_inum.no_addr) != ip->i_no_addr) + goto out; + if (be64_to_cpu(dent->de_inum.no_formal_ino) != + ip->i_no_formal_ino) + goto out; + if (unlikely(IF2DT(ip->i_inode.i_mode) != + be16_to_cpu(dent->de_type))) { + gfs2_consist_inode(GFS2_I(dir)); + ret = -EIO; + goto out; + } + } + ret = 0; +out: brelse(bh); - return 0; } - return -ENOENT; + return ret; } static int dir_new_leaf(struct inode *inode, const struct qstr *name) @@ -1497,7 +1548,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) u32 index; u64 bn; - index = name->hash >> (32 - ip->i_di.di_depth); + index = name->hash >> (32 - ip->i_depth); error = get_first_leaf(ip, index, &obh); if (error) return error; @@ -1527,8 +1578,8 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) if (error) return error; gfs2_trans_add_bh(ip->i_gl, bh, 1); - ip->i_di.di_blocks++; - gfs2_dinode_out(&ip->i_di, bh->b_data); + gfs2_add_inode_blocks(&ip->i_inode, 1); + gfs2_dinode_out(ip, bh->b_data); brelse(bh); return 0; } @@ -1544,7 +1595,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) */ int gfs2_dir_add(struct inode *inode, const struct qstr *name, - const struct gfs2_inum *inum, unsigned type) + const struct gfs2_inode *nip, unsigned type) { struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; @@ -1559,25 +1610,25 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, if (IS_ERR(dent)) return PTR_ERR(dent); dent = gfs2_init_dirent(inode, dent, name, bh); - gfs2_inum_out(inum, (char *)&dent->de_inum); + gfs2_inum_out(nip, dent); dent->de_type = cpu_to_be16(type); - if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { + if (ip->i_diskflags & GFS2_DIF_EXHASH) { leaf = (struct gfs2_leaf *)bh->b_data; - leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1); + be16_add_cpu(&leaf->lf_entries, 1); } brelse(bh); error = gfs2_meta_inode_buffer(ip, &bh); if (error) break; gfs2_trans_add_bh(ip->i_gl, bh, 1); - ip->i_di.di_entries++; - ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&ip->i_di, bh->b_data); + ip->i_entries++; + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_dinode_out(ip, bh->b_data); brelse(bh); error = 0; break; } - if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) { + if (!(ip->i_diskflags & GFS2_DIF_EXHASH)) { error = dir_make_exhash(inode); if (error) break; @@ -1588,7 +1639,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, continue; if (error < 0) break; - if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { + if (ip->i_depth < GFS2_DIR_MAX_DEPTH) { error = dir_double_exhash(ip); if (error) break; @@ -1640,7 +1691,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) } dirent_del(dip, bh, prev, dent); - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { + if (dip->i_diskflags & GFS2_DIF_EXHASH) { struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data; u16 entries = be16_to_cpu(leaf->lf_entries); if (!entries) @@ -1653,12 +1704,12 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) if (error) return error; - if (!dip->i_di.di_entries) + if (!dip->i_entries) gfs2_consist_inode(dip); gfs2_trans_add_bh(dip->i_gl, bh, 1); - dip->i_di.di_entries--; - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&dip->i_di, bh->b_data); + dip->i_entries--; + dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; + gfs2_dinode_out(dip, bh->b_data); brelse(bh); mark_inode_dirty(&dip->i_inode); @@ -1679,7 +1730,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) */ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, - struct gfs2_inum *inum, unsigned int new_type) + const struct gfs2_inode *nip, unsigned int new_type) { struct buffer_head *bh; struct gfs2_dirent *dent; @@ -1694,10 +1745,10 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, return PTR_ERR(dent); gfs2_trans_add_bh(dip->i_gl, bh, 1); - gfs2_inum_out(inum, (char *)&dent->de_inum); + gfs2_inum_out(nip, dent); dent->de_type = cpu_to_be16(new_type); - if (dip->i_di.di_flags & GFS2_DIF_EXHASH) { + if (dip->i_diskflags & GFS2_DIF_EXHASH) { brelse(bh); error = gfs2_meta_inode_buffer(dip, &bh); if (error) @@ -1705,8 +1756,8 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, gfs2_trans_add_bh(dip->i_gl, bh, 1); } - dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); - gfs2_dinode_out(&dip->i_di, bh->b_data); + dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; + gfs2_dinode_out(dip, bh->b_data); brelse(bh); return 0; } @@ -1725,20 +1776,20 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *bh; struct gfs2_leaf *leaf; - uint32_t hsize, len; - uint32_t ht_offset, lp_offset, ht_offset_cur = -1; - uint32_t index = 0; - uint64_t *lp; - uint64_t leaf_no; + u32 hsize, len; + u32 ht_offset, lp_offset, ht_offset_cur = -1; + u32 index = 0; + __be64 *lp; + u64 leaf_no; int error = 0; - hsize = 1 << dip->i_di.di_depth; - if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + hsize = 1 << dip->i_depth; + if (hsize * sizeof(u64) != dip->i_disksize) { gfs2_consist_inode(dip); return -EIO; } - lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS); if (!lp) return -ENOMEM; @@ -1748,8 +1799,8 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (ht_offset_cur != ht_offset) { error = gfs2_dir_read_data(dip, (char *)lp, - ht_offset * sizeof(uint64_t), - sdp->sd_hash_bsize); + ht_offset * sizeof(__be64), + sdp->sd_hash_bsize, 1); if (error != sdp->sd_hash_bsize) { if (error >= 0) error = -EIO; @@ -1764,7 +1815,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) if (error) goto out; leaf = (struct gfs2_leaf *)bh->b_data; - len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); + len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); brelse(bh); error = lc(dip, index, len, leaf_no, data); @@ -1798,32 +1849,35 @@ out: * Returns: errno */ -static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, - uint64_t leaf_no, void *data) +static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, + u64 leaf_no, void *data) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_leaf *tmp_leaf; struct gfs2_rgrp_list rlist; struct buffer_head *bh, *dibh; - uint64_t blk, nblk; + u64 blk, nblk; unsigned int rg_blocks = 0, l_blocks = 0; char *ht; - unsigned int x, size = len * sizeof(uint64_t); + unsigned int x, size = len * sizeof(u64); int error; memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); - ht = kzalloc(size, GFP_KERNEL); + ht = kzalloc(size, GFP_NOFS); if (!ht) return -ENOMEM; - gfs2_alloc_get(dip); + if (!gfs2_alloc_get(dip)) { + error = -ENOMEM; + goto out; + } error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) - goto out; + goto out_put; - error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh); + error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh); if (error) goto out_qs; @@ -1841,12 +1895,12 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, l_blocks++; } - gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; rgd = rlist.rl_ghs[x].gh_gl->gl_object; - rg_blocks += rgd->rd_ri.ri_length; + rg_blocks += rgd->rd_length; } error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); @@ -1868,13 +1922,10 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, brelse(bh); gfs2_free_meta(dip, blk, 1); - - if (!dip->i_di.di_blocks) - gfs2_consist_inode(dip); - dip->i_di.di_blocks--; + gfs2_add_inode_blocks(&dip->i_inode, -1); } - error = gfs2_dir_write_data(dip, ht, index * sizeof(uint64_t), size); + error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size); if (error != size) { if (error >= 0) error = -EIO; @@ -1886,7 +1937,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, uint32_t index, uint32_t len, goto out_end_trans; gfs2_trans_add_bh(dip->i_gl, dibh, 1); - gfs2_dinode_out(&dip->i_di, dibh->b_data); + gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); out_end_trans: @@ -1895,11 +1946,12 @@ out_rg_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); out_rlist: gfs2_rlist_free(&rlist); - gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh); + gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh); out_qs: gfs2_quota_unhold(dip); -out: +out_put: gfs2_alloc_put(dip); +out: kfree(ht); return error; }