提交 71b86f56 编写于 作者: S Steven Whitehouse

[GFS2] Further updates to dir and logging code

This reduces the size of the directory code by about 3k and gets
readdir() to use the functions which were introduced in the previous
directory code update.

Two memory allocations are merged into one. Eliminates zeroing of some
buffers which were never used before they were initialised by
other data.

There is still scope for further improvement in the directory code.

On the logging side, a hand created mutex has been replaced by a
standard Linux mutex in the log allocation code.
Signed-off-by: NSteven Whitehouse <swhiteho@redhat.com>
上级 94aabbd9
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -344,7 +345,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, ...@@ -344,7 +345,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf,
} }
typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent,
const struct qstr *name); const struct qstr *name,
void *opaque);
static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent,
const struct qstr *name, int ret) const struct qstr *name, int ret)
...@@ -358,13 +360,15 @@ static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, ...@@ -358,13 +360,15 @@ static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent,
} }
static int gfs2_dirent_find(const struct gfs2_dirent *dent, static int gfs2_dirent_find(const struct gfs2_dirent *dent,
const struct qstr *name) const struct qstr *name,
void *opaque)
{ {
return __gfs2_dirent_find(dent, name, 1); return __gfs2_dirent_find(dent, name, 1);
} }
static int gfs2_dirent_prev(const struct gfs2_dirent *dent, static int gfs2_dirent_prev(const struct gfs2_dirent *dent,
const struct qstr *name) const struct qstr *name,
void *opaque)
{ {
return __gfs2_dirent_find(dent, name, 2); return __gfs2_dirent_find(dent, name, 2);
} }
...@@ -374,7 +378,8 @@ static int gfs2_dirent_prev(const struct gfs2_dirent *dent, ...@@ -374,7 +378,8 @@ static int gfs2_dirent_prev(const struct gfs2_dirent *dent,
* name->len holds size of block. * name->len holds size of block.
*/ */
static int gfs2_dirent_last(const struct gfs2_dirent *dent, static int gfs2_dirent_last(const struct gfs2_dirent *dent,
const struct qstr *name) const struct qstr *name,
void *opaque)
{ {
const char *start = name->name; const char *start = name->name;
const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len); const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len);
...@@ -384,17 +389,36 @@ static int gfs2_dirent_last(const struct gfs2_dirent *dent, ...@@ -384,17 +389,36 @@ static int gfs2_dirent_last(const struct gfs2_dirent *dent,
} }
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)
{ {
unsigned required = GFS2_DIRENT_SIZE(name->len); unsigned required = GFS2_DIRENT_SIZE(name->len);
unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
unsigned totlen = be16_to_cpu(dent->de_rec_len); unsigned totlen = be16_to_cpu(dent->de_rec_len);
if (!dent->de_inum.no_addr)
actual = GFS2_DIRENT_SIZE(0);
if ((totlen - actual) >= required) if ((totlen - actual) >= required)
return 1; return 1;
return 0; return 0;
} }
struct dirent_gather {
const struct gfs2_dirent **pdent;
unsigned offset;
};
static int gfs2_dirent_gather(const struct gfs2_dirent *dent,
const struct qstr *name,
void *opaque)
{
struct dirent_gather *g = opaque;
if (dent->de_inum.no_addr) {
g->pdent[g->offset++] = dent;
}
return 0;
}
/* /*
* Other possible things to check: * Other possible things to check:
* - Inode located within filesystem size (and on valid block) * - Inode located within filesystem size (and on valid block)
...@@ -431,19 +455,12 @@ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, ...@@ -431,19 +455,12 @@ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset,
return -EIO; return -EIO;
} }
static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, static int gfs2_dirent_offset(const void *buf)
void *buf,
unsigned int len, gfs2_dscan_t scan,
const struct qstr *name)
{ {
struct gfs2_meta_header *h = buf; const struct gfs2_meta_header *h = buf;
struct gfs2_dirent *dent, *prev; int offset;
unsigned offset;
unsigned size;
int ret = 0;
BUG_ON(buf == NULL); BUG_ON(buf == NULL);
BUG_ON(name == NULL);
switch(be16_to_cpu(h->mh_type)) { switch(be16_to_cpu(h->mh_type)) {
case GFS2_METATYPE_LF: case GFS2_METATYPE_LF:
...@@ -455,14 +472,36 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, ...@@ -455,14 +472,36 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode,
default: default:
goto wrong_type; goto wrong_type;
} }
return offset;
wrong_type:
printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n",
be16_to_cpu(h->mh_type));
return -1;
}
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)
{
struct gfs2_dirent *dent, *prev;
unsigned offset;
unsigned size;
int ret = 0;
ret = gfs2_dirent_offset(buf);
if (ret < 0)
goto consist_inode;
offset = ret;
prev = NULL; prev = NULL;
dent = (struct gfs2_dirent *)(buf + offset); dent = (struct gfs2_dirent *)(buf + offset);
size = be16_to_cpu(dent->de_rec_len); size = be16_to_cpu(dent->de_rec_len);
if (gfs2_check_dirent(dent, offset, size, len, 1)) if (gfs2_check_dirent(dent, offset, size, len, 1))
goto consist_inode; goto consist_inode;
do { do {
ret = scan(dent, name); ret = scan(dent, name, opaque);
if (ret) if (ret)
break; break;
offset += size; offset += size;
...@@ -487,9 +526,6 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, ...@@ -487,9 +526,6 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
wrong_type:
printk(KERN_WARNING "gfs2_scan_dirent: %p wrong block type %u\n", scan,
be16_to_cpu(h->mh_type));
consist_inode: consist_inode:
gfs2_consist_inode(inode->u.generic_ip); gfs2_consist_inode(inode->u.generic_ip);
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
...@@ -651,7 +687,8 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, ...@@ -651,7 +687,8 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode,
const struct qstr *name) const struct qstr *name)
{ {
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_find_space, name); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
gfs2_dirent_find_space, name, NULL);
if (!dent || IS_ERR(dent)) if (!dent || IS_ERR(dent))
return dent; return dent;
return gfs2_init_dirent(inode, dent, name, bh); return gfs2_init_dirent(inode, dent, name, bh);
...@@ -734,7 +771,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, ...@@ -734,7 +771,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
return ERR_PTR(error); return ERR_PTR(error);
do { do {
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
scan, name); scan, name, NULL);
if (dent) if (dent)
goto got_dent; goto got_dent;
leaf = (struct gfs2_leaf *)bh->b_data; leaf = (struct gfs2_leaf *)bh->b_data;
...@@ -751,7 +788,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, ...@@ -751,7 +788,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
error = gfs2_meta_inode_buffer(ip, &bh); error = gfs2_meta_inode_buffer(ip, &bh);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL);
got_dent: got_dent:
*pbh = bh; *pbh = bh;
return dent; return dent;
...@@ -764,6 +801,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, ...@@ -764,6 +801,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
struct gfs2_leaf *leaf; struct gfs2_leaf *leaf;
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
struct qstr name = { .name = "", .len = 0, .hash = 0 };
if (!bh) if (!bh)
return NULL; return NULL;
gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1);
...@@ -775,12 +813,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, ...@@ -775,12 +813,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
leaf->lf_next = cpu_to_be64(0); leaf->lf_next = cpu_to_be64(0);
memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved));
dent = (struct gfs2_dirent *)(leaf+1); dent = (struct gfs2_dirent *)(leaf+1);
dent->de_inum.no_formal_ino = cpu_to_be64(0); gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
dent->de_inum.no_addr = cpu_to_be64(0);
dent->de_hash = cpu_to_be32(0);
dent->de_rec_len = cpu_to_be16(bh->b_size - sizeof(struct gfs2_leaf));
dent->de_name_len = cpu_to_be16(0);
dent->de_type = cpu_to_be16(0);
*pbh = bh; *pbh = bh;
return leaf; return leaf;
} }
...@@ -831,7 +864,7 @@ static int dir_make_exhash(struct inode *inode) ...@@ -831,7 +864,7 @@ static int dir_make_exhash(struct inode *inode)
sizeof(struct gfs2_leaf); sizeof(struct gfs2_leaf);
args.name = bh->b_data; args.name = bh->b_data;
dent = gfs2_dirent_scan(dip->i_vnode, bh->b_data, bh->b_size, dent = gfs2_dirent_scan(dip->i_vnode, bh->b_data, bh->b_size,
gfs2_dirent_last, &args); gfs2_dirent_last, &args, NULL);
if (!dent) { if (!dent) {
brelse(bh); brelse(bh);
brelse(dibh); brelse(dibh);
...@@ -939,7 +972,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -939,7 +972,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
lp[x] = cpu_to_be64(bn); lp[x] = cpu_to_be64(bn);
error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t),
half_len * sizeof(uint64_t)); half_len * sizeof(uint64_t));
if (error != half_len * sizeof(uint64_t)) { if (error != half_len * sizeof(uint64_t)) {
if (error >= 0) if (error >= 0)
error = -EIO; error = -EIO;
...@@ -965,7 +998,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -965,7 +998,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
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(dip->i_vnode, nbh, &str); new = gfs2_dirent_alloc(inode, nbh, &str);
if (IS_ERR(new)) { if (IS_ERR(new)) {
error = PTR_ERR(new); error = PTR_ERR(new);
break; break;
...@@ -1154,10 +1187,10 @@ static int compare_dents(const void *a, const void *b) ...@@ -1154,10 +1187,10 @@ static int compare_dents(const void *a, const void *b)
static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset,
void *opaque, gfs2_filldir_t filldir, void *opaque, gfs2_filldir_t filldir,
struct gfs2_dirent **darr, uint32_t entries, const struct gfs2_dirent **darr, uint32_t entries,
int *copied) int *copied)
{ {
struct gfs2_dirent *dent, *dent_next; const struct gfs2_dirent *dent, *dent_next;
struct gfs2_inum inum; struct gfs2_inum inum;
uint64_t off, off_next; uint64_t off, off_next;
unsigned int x, y; unsigned int x, y;
...@@ -1216,189 +1249,74 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, ...@@ -1216,189 +1249,74 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset,
return 0; return 0;
} }
/** static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
* do_filldir_single - Read directory entries out of a single block gfs2_filldir_t filldir, int *copied,
* @dip: The GFS2 inode unsigned *depth, u64 leaf_no)
* @offset: The offset in the file to read from
* @opaque: opaque data to pass to filldir
* @filldir: The function to pass entries to
* @bh: the block
* @entries: the number of entries in the block
* @copied: pointer to int that's non-zero if a entry has been copied out
*
* Returns: errno, >0 on exception from filldir
*/
static int do_filldir_single(struct gfs2_inode *dip, uint64_t *offset,
void *opaque, gfs2_filldir_t filldir,
struct buffer_head *bh, uint32_t entries,
int *copied)
{ {
struct gfs2_dirent **darr; struct gfs2_inode *ip = inode->u.generic_ip;
struct gfs2_dirent *de; struct buffer_head *bh;
unsigned int e = 0; struct gfs2_leaf *lf;
int error; unsigned entries = 0;
unsigned leaves = 0;
if (!entries) const struct gfs2_dirent **darr, *dent;
return 0; struct dirent_gather g;
struct buffer_head **larr;
darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL); int leaf = 0;
if (!darr) int error, i;
return -ENOMEM; u64 lfn = leaf_no;
dirent_first(dip, bh, &de);
do { do {
if (!de->de_inum.no_addr) error = get_leaf(ip, lfn, &bh);
continue;
if (e >= entries) {
gfs2_consist_inode(dip);
error = -EIO;
goto out;
}
darr[e++] = de;
} while (dirent_next(dip, bh, &de) == 0);
if (e != entries) {
gfs2_consist_inode(dip);
error = -EIO;
goto out;
}
error = do_filldir_main(dip, offset, opaque, filldir, darr,
entries, copied);
out:
kfree(darr);
return error;
}
/**
* do_filldir_multi - Read directory entries out of a linked leaf list
* @dip: The GFS2 inode
* @offset: The offset in the file to read from
* @opaque: opaque data to pass to filldir
* @filldir: The function to pass entries to
* @bh: the first leaf in the list
* @copied: pointer to int that's non-zero if a entry has been copied out
*
* Returns: errno, >0 on exception from filldir
*/
static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset,
void *opaque, gfs2_filldir_t filldir,
struct buffer_head *bh, int *copied)
{
struct buffer_head **larr = NULL;
struct gfs2_dirent **darr;
struct gfs2_leaf *leaf;
struct buffer_head *tmp_bh;
struct gfs2_dirent *de;
unsigned int entries, e = 0;
unsigned int leaves = 0, l = 0;
unsigned int x;
uint64_t ln;
int error = 0;
/* Count leaves and entries */
leaf = (struct gfs2_leaf *)bh->b_data;
entries = be16_to_cpu(leaf->lf_entries);
ln = be64_to_cpu(leaf->lf_next);
while (ln) {
error = get_leaf(dip, ln, &tmp_bh);
if (error) if (error)
return error; goto out;
lf = (struct gfs2_leaf *)bh->b_data;
leaf = (struct gfs2_leaf *)tmp_bh->b_data; if (leaves == 0)
if (leaf->lf_entries) { *depth = be16_to_cpu(lf->lf_depth);
entries += be16_to_cpu(leaf->lf_entries); entries += be16_to_cpu(lf->lf_entries);
leaves++; leaves++;
} lfn = be64_to_cpu(lf->lf_next);
ln = be64_to_cpu(leaf->lf_next); brelse(bh);
} while(lfn);
brelse(tmp_bh);
}
if (!entries) if (!entries)
return 0; return 0;
if (leaves) { error = -ENOMEM;
larr = kcalloc(leaves, sizeof(struct buffer_head *),GFP_KERNEL); larr = kmalloc((leaves + entries) * sizeof(void*), GFP_KERNEL);
if (!larr) if (!larr)
return -ENOMEM; goto out;
} darr = (const struct gfs2_dirent **)(larr + leaves);
g.pdent = darr;
darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL); g.offset = 0;
if (!darr) { lfn = leaf_no;
kfree(larr);
return -ENOMEM;
}
leaf = (struct gfs2_leaf *)bh->b_data;
if (leaf->lf_entries) {
dirent_first(dip, bh, &de);
do {
if (!de->de_inum.no_addr)
continue;
if (e >= entries) {
gfs2_consist_inode(dip);
error = -EIO;
goto out;
}
darr[e++] = de;
} while (dirent_next(dip, bh, &de) == 0);
}
ln = be64_to_cpu(leaf->lf_next);
while (ln) { do {
error = get_leaf(dip, ln, &tmp_bh); error = get_leaf(ip, lfn, &bh);
if (error) if (error)
goto out; goto out_kfree;
lf = (struct gfs2_leaf *)bh->b_data;
leaf = (struct gfs2_leaf *)tmp_bh->b_data; lfn = be64_to_cpu(lf->lf_next);
if (leaf->lf_entries) { if (lf->lf_entries) {
dirent_first(dip, tmp_bh, &de); dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
do { gfs2_dirent_gather, NULL, &g);
if (!de->de_inum.no_addr) error = PTR_ERR(dent);
continue; if (IS_ERR(dent)) {
if (e >= entries) { goto out_kfree;
gfs2_consist_inode(dip); }
error = -EIO; error = 0;
goto out; larr[leaf++] = bh;
}
darr[e++] = de;
} while (dirent_next(dip, tmp_bh, &de) == 0);
larr[l++] = tmp_bh;
ln = be64_to_cpu(leaf->lf_next);
} else { } else {
ln = be64_to_cpu(leaf->lf_next); brelse(bh);
brelse(tmp_bh);
} }
} } while(lfn);
if (gfs2_assert_withdraw(dip->i_sbd, l == leaves)) { error = do_filldir_main(ip, offset, opaque, filldir, darr,
error = -EIO;
goto out;
}
if (e != entries) {
gfs2_consist_inode(dip);
error = -EIO;
goto out;
}
error = do_filldir_main(dip, offset, opaque, filldir, darr,
entries, copied); entries, copied);
out_kfree:
out: for(i = 0; i < leaf; i++)
kfree(darr); brelse(larr[i]);
for (x = 0; x < l; x++)
brelse(larr[x]);
kfree(larr); kfree(larr);
out:
return error; return error;
} }
...@@ -1412,18 +1330,18 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, ...@@ -1412,18 +1330,18 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset,
* Returns: errno * Returns: errno
*/ */
static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque,
gfs2_filldir_t filldir) gfs2_filldir_t filldir)
{ {
struct gfs2_inode *dip = inode->u.generic_ip;
struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_sbd *sdp = dip->i_sbd;
struct buffer_head *bh; uint32_t hsize, len = 0;
struct gfs2_leaf *leaf;
uint32_t hsize, len;
uint32_t ht_offset, lp_offset, ht_offset_cur = -1; uint32_t ht_offset, lp_offset, ht_offset_cur = -1;
uint32_t hash, index; uint32_t hash, index;
uint64_t *lp; uint64_t *lp;
int copied = 0; int copied = 0;
int error = 0; int error = 0;
unsigned depth;
hsize = 1 << dip->i_di.di_depth; hsize = 1 << dip->i_di.di_depth;
if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { if (hsize * sizeof(uint64_t) != dip->i_di.di_size) {
...@@ -1454,61 +1372,66 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, ...@@ -1454,61 +1372,66 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque,
ht_offset_cur = ht_offset; ht_offset_cur = ht_offset;
} }
error = get_leaf(dip, be64_to_cpu(lp[lp_offset]), &bh); error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
&copied, &depth,
be64_to_cpu(lp[lp_offset]));
if (error) if (error)
goto out; break;
leaf = (struct gfs2_leaf *)bh->b_data;
if (leaf->lf_next)
error = do_filldir_multi(dip, offset, opaque, filldir,
bh, &copied);
else
error = do_filldir_single(dip, offset, opaque, filldir,
bh,
be16_to_cpu(leaf->lf_entries),
&copied);
brelse(bh);
if (error) {
if (error > 0)
error = 0;
goto out;
}
len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); len = 1 << (dip->i_di.di_depth - depth);
index = (index & ~(len - 1)) + len; index = (index & ~(len - 1)) + len;
} }
out: out:
kfree(lp); kfree(lp);
if (error > 0)
error = 0;
return error; return error;
} }
static int dir_l_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque,
gfs2_filldir_t filldir) gfs2_filldir_t filldir)
{ {
struct gfs2_inode *dip = inode->u.generic_ip;
struct dirent_gather g;
const struct gfs2_dirent **darr, *dent;
struct buffer_head *dibh; struct buffer_head *dibh;
int copied = 0; int copied = 0;
int error; int error;
if (!dip->i_di.di_entries)
return 0;
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
return dir_e_read(inode, offset, opaque, filldir);
if (!gfs2_is_stuffed(dip)) { if (!gfs2_is_stuffed(dip)) {
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
return -EIO; return -EIO;
} }
if (!dip->i_di.di_entries)
return 0;
error = gfs2_meta_inode_buffer(dip, &dibh); error = gfs2_meta_inode_buffer(dip, &dibh);
if (error) if (error)
return error; return error;
error = do_filldir_single(dip, offset, error = -ENOMEM;
opaque, filldir, darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
dibh, dip->i_di.di_entries, GFP_KERNEL);
&copied); if (darr) {
g.pdent = darr;
g.offset = 0;
dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,
gfs2_dirent_gather, NULL, &g);
if (IS_ERR(dent)) {
error = PTR_ERR(dent);
goto out;
}
error = do_filldir_main(dip, offset, opaque, filldir, darr,
dip->i_di.di_entries, &copied);
out:
kfree(darr);
}
if (error > 0) if (error > 0)
error = 0; error = 0;
...@@ -1694,7 +1617,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) ...@@ -1694,7 +1617,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
return PTR_ERR(dent); return PTR_ERR(dent);
} }
/* If not first in block, adjust pointers accordingly */ /* If not first in block, adjust pointers accordingly */
if (gfs2_dirent_find(dent, name) == 0) { if (gfs2_dirent_find(dent, name, NULL) == 0) {
prev = dent; prev = dent;
dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len));
} }
...@@ -1724,19 +1647,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) ...@@ -1724,19 +1647,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
return error; return error;
} }
int gfs2_dir_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque,
gfs2_filldir_t filldir)
{
int error;
if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
error = dir_e_read(dip, offset, opaque, filldir);
else
error = dir_l_read(dip, offset, opaque, filldir);
return error;
}
/** /**
* gfs2_dir_mvino - Change inode number of directory entry * gfs2_dir_mvino - Change inode number of directory entry
* @dip: The GFS2 inode * @dip: The GFS2 inode
......
...@@ -32,7 +32,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *filename, ...@@ -32,7 +32,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
int gfs2_dir_add(struct inode *inode, const struct qstr *filename, int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
const struct gfs2_inum *inum, unsigned int type); const struct gfs2_inum *inum, unsigned int type);
int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename); int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
int gfs2_dir_read(struct gfs2_inode *dip, uint64_t * offset, void *opaque, int gfs2_dir_read(struct inode *inode, uint64_t * offset, void *opaque,
gfs2_filldir_t filldir); gfs2_filldir_t filldir);
int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
struct gfs2_inum *new_inum, unsigned int new_type); struct gfs2_inum *new_inum, unsigned int new_type);
...@@ -44,6 +44,19 @@ int gfs2_diradd_alloc_required(struct inode *dir, ...@@ -44,6 +44,19 @@ int gfs2_diradd_alloc_required(struct inode *dir,
int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new,
struct buffer_head **bhp); struct buffer_head **bhp);
static inline uint32_t gfs2_disk_hash(const char *data, int len)
{
return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF;
}
static inline void gfs2_str2qstr(struct qstr *name, const char *fname)
{
name->name = fname;
name->len = strlen(fname);
name->hash = gfs2_disk_hash(name->name, name->len);
}
/* N.B. This probably ought to take inum & type as args as well */ /* N.B. This probably ought to take inum & type as args as well */
static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent) static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent)
{ {
......
...@@ -634,8 +634,7 @@ struct gfs2_sbd { ...@@ -634,8 +634,7 @@ struct gfs2_sbd {
struct list_head sd_log_le_databuf; struct list_head sd_log_le_databuf;
unsigned int sd_log_blks_free; unsigned int sd_log_blks_free;
struct list_head sd_log_blks_list; struct mutex sd_log_reserve_mutex;
wait_queue_head_t sd_log_blks_wait;
uint64_t sd_log_sequence; uint64_t sd_log_sequence;
unsigned int sd_log_head; unsigned int sd_log_head;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -701,9 +702,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) ...@@ -701,9 +702,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
{ {
struct qstr qstr; struct qstr qstr;
qstr.name = name; gfs2_str2qstr(&qstr, name);
qstr.len = strlen(name);
qstr.hash = gfs2_disk_hash(qstr.name, qstr.len);
return gfs2_lookupi(dip, &qstr, 1, NULL); return gfs2_lookupi(dip, &qstr, 1, NULL);
} }
...@@ -1389,9 +1388,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, ...@@ -1389,9 +1388,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name,
if (error) if (error)
return error; return error;
dotname.len = 1; gfs2_str2qstr(&dotname, ".");
dotname.name = ".";
dotname.hash = gfs2_disk_hash(dotname.name, dotname.len);
error = gfs2_dir_del(ip, &dotname); error = gfs2_dir_del(ip, &dotname);
if (error) if (error)
return error; return error;
...@@ -1487,10 +1484,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) ...@@ -1487,10 +1484,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
struct qstr dotdot; struct qstr dotdot;
int error = 0; int error = 0;
memset(&dotdot, 0, sizeof(struct qstr)); gfs2_str2qstr(&dotdot, "..");
dotdot.name = "..";
dotdot.len = 2;
dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len);
igrab(dir); igrab(dir);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -24,18 +25,13 @@ ...@@ -24,18 +25,13 @@
#include "lops.h" #include "lops.h"
#include "meta_io.h" #include "meta_io.h"
#include "util.h" #include "util.h"
#include "dir.h"
#define PULL 1 #define PULL 1
static void do_lock_wait(struct gfs2_sbd *sdp, wait_queue_head_t *wq,
atomic_t *a)
{
wait_event(*wq, atomic_read(a) ? 0 : 1);
}
static void lock_for_trans(struct gfs2_sbd *sdp) static void lock_for_trans(struct gfs2_sbd *sdp)
{ {
do_lock_wait(sdp, &sdp->sd_log_trans_wq, &sdp->sd_log_flush_count); wait_event(sdp->sd_log_trans_wq, atomic_read(&sdp->sd_log_flush_count) ? 0 : 1);
atomic_inc(&sdp->sd_log_trans_count); atomic_inc(&sdp->sd_log_trans_count);
} }
...@@ -49,7 +45,7 @@ static void unlock_from_trans(struct gfs2_sbd *sdp) ...@@ -49,7 +45,7 @@ static void unlock_from_trans(struct gfs2_sbd *sdp)
static void gfs2_lock_for_flush(struct gfs2_sbd *sdp) static void gfs2_lock_for_flush(struct gfs2_sbd *sdp)
{ {
atomic_inc(&sdp->sd_log_flush_count); atomic_inc(&sdp->sd_log_flush_count);
do_lock_wait(sdp, &sdp->sd_log_flush_wq, &sdp->sd_log_trans_count); wait_event(sdp->sd_log_flush_wq, atomic_read(&sdp->sd_log_trans_count) ? 0 : 1);
} }
static void gfs2_unlock_from_flush(struct gfs2_sbd *sdp) static void gfs2_unlock_from_flush(struct gfs2_sbd *sdp)
...@@ -191,37 +187,19 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) ...@@ -191,37 +187,19 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
{ {
LIST_HEAD(list);
unsigned int try = 0; unsigned int try = 0;
if (gfs2_assert_warn(sdp, blks) || if (gfs2_assert_warn(sdp, blks) ||
gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks)) gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
return -EINVAL; return -EINVAL;
mutex_lock(&sdp->sd_log_reserve_mutex);
for (;;) { for (;;) {
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
if (list_empty(&list)) {
list_add_tail(&list, &sdp->sd_log_blks_list);
while (sdp->sd_log_blks_list.next != &list) {
DECLARE_WAITQUEUE(__wait_chan, current);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&sdp->sd_log_blks_wait,
&__wait_chan);
gfs2_log_unlock(sdp);
schedule();
gfs2_log_lock(sdp);
remove_wait_queue(&sdp->sd_log_blks_wait,
&__wait_chan);
set_current_state(TASK_RUNNING);
}
}
/* Never give away the last block so we can
always pull the tail if we need to. */
if (sdp->sd_log_blks_free > blks) { if (sdp->sd_log_blks_free > blks) {
sdp->sd_log_blks_free -= blks; sdp->sd_log_blks_free -= blks;
list_del(&list);
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
wake_up(&sdp->sd_log_blks_wait); mutex_unlock(&sdp->sd_log_reserve_mutex);
break; break;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -153,7 +154,7 @@ static int gfs2_get_name(struct dentry *parent, char *name, ...@@ -153,7 +154,7 @@ static int gfs2_get_name(struct dentry *parent, char *name,
if (error) if (error)
return error; return error;
error = gfs2_dir_read(dip, &offset, &gnfd, get_name_filldir); error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
...@@ -165,12 +166,11 @@ static int gfs2_get_name(struct dentry *parent, char *name, ...@@ -165,12 +166,11 @@ static int gfs2_get_name(struct dentry *parent, char *name,
static struct dentry *gfs2_get_parent(struct dentry *child) static struct dentry *gfs2_get_parent(struct dentry *child)
{ {
struct qstr dotdot = { .name = "..", .len = 2 }; struct qstr dotdot;
struct inode *inode; struct inode *inode;
struct dentry *dentry; struct dentry *dentry;
dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len); gfs2_str2qstr(&dotdot, "..");
inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL); inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);
if (!inode) if (!inode)
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/ext2_fs.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -39,6 +41,7 @@ ...@@ -39,6 +41,7 @@
#include "rgrp.h" #include "rgrp.h"
#include "trans.h" #include "trans.h"
#include "util.h" #include "util.h"
#include "eaops.h"
/* "bad" is for NFS support */ /* "bad" is for NFS support */
struct filldir_bad_entry { struct filldir_bad_entry {
...@@ -357,7 +360,8 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, ...@@ -357,7 +360,8 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length,
static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) static int readdir_reg(struct file *file, void *dirent, filldir_t filldir)
{ {
struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip; struct inode *dir = file->f_mapping->host;
struct gfs2_inode *dip = dir->u.generic_ip;
struct filldir_reg fdr; struct filldir_reg fdr;
struct gfs2_holder d_gh; struct gfs2_holder d_gh;
uint64_t offset = file->f_pos; uint64_t offset = file->f_pos;
...@@ -375,7 +379,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) ...@@ -375,7 +379,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir)
return error; return error;
} }
error = gfs2_dir_read(dip, &offset, &fdr, filldir_reg_func); error = gfs2_dir_read(dir, &offset, &fdr, filldir_reg_func);
gfs2_glock_dq_uninit(&d_gh); gfs2_glock_dq_uninit(&d_gh);
...@@ -446,7 +450,8 @@ static int filldir_bad_func(void *opaque, const char *name, unsigned int length, ...@@ -446,7 +450,8 @@ static int filldir_bad_func(void *opaque, const char *name, unsigned int length,
static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) static int readdir_bad(struct file *file, void *dirent, filldir_t filldir)
{ {
struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip; struct inode *dir = file->f_mapping->host;
struct gfs2_inode *dip = dir->u.generic_ip;
struct gfs2_sbd *sdp = dip->i_sbd; struct gfs2_sbd *sdp = dip->i_sbd;
struct filldir_reg fdr; struct filldir_reg fdr;
unsigned int entries, size; unsigned int entries, size;
...@@ -479,7 +484,7 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) ...@@ -479,7 +484,7 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir)
goto out; goto out;
} }
error = gfs2_dir_read(dip, &offset, fdb, filldir_bad_func); error = gfs2_dir_read(dir, &offset, fdb, filldir_bad_func);
gfs2_glock_dq_uninit(&d_gh); gfs2_glock_dq_uninit(&d_gh);
...@@ -531,6 +536,210 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) ...@@ -531,6 +536,210 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
return error; return error;
} }
const struct gfs2_flag_eattr {
u32 flag;
u32 ext2;
} gfs2_flag_eattrs[] = {
{
.flag = GFS2_DIF_IMMUTABLE,
.ext2 = EXT2_IMMUTABLE_FL,
}, {
.flag = GFS2_DIF_APPENDONLY,
.ext2 = EXT2_APPEND_FL,
}, {
.flag = GFS2_DIF_JDATA,
.ext2 = EXT2_JOURNAL_DATA_FL,
}, {
.flag = GFS2_DIF_EXHASH,
.ext2 = EXT2_INDEX_FL,
}, {
.flag = GFS2_DIF_EA_INDIRECT,
}, {
.flag = GFS2_DIF_DIRECTIO,
}, {
.flag = GFS2_DIF_NOATIME,
.ext2 = EXT2_NOATIME_FL,
}, {
.flag = GFS2_DIF_SYNC,
.ext2 = EXT2_SYNC_FL,
}, {
.flag = GFS2_DIF_SYSTEM,
}, {
.flag = GFS2_DIF_TRUNC_IN_PROG,
}, {
.flag = GFS2_DIF_INHERIT_JDATA,
}, {
.flag = GFS2_DIF_INHERIT_DIRECTIO,
}, {
},
};
static const struct gfs2_flag_eattr *get_by_ext2(u32 ext2)
{
const struct gfs2_flag_eattr *p = gfs2_flag_eattrs;
for(; p->flag; p++) {
if (ext2 == p->ext2)
return p;
}
return NULL;
}
static const struct gfs2_flag_eattr *get_by_gfs2(u32 gfs2)
{
const struct gfs2_flag_eattr *p = gfs2_flag_eattrs;
for(; p->flag; p++) {
if (gfs2 == p->flag)
return p;
}
return NULL;
}
static u32 gfs2_flags_to_ext2(u32 gfs2)
{
const struct gfs2_flag_eattr *ea;
u32 ext2 = 0;
u32 mask = 1;
for(; mask != 0; mask <<=1) {
if (mask & gfs2) {
ea = get_by_gfs2(mask);
if (ea)
ext2 |= ea->ext2;
}
}
return ext2;
}
static int gfs2_flags_from_ext2(u32 *gfs2, u32 ext2)
{
const struct gfs2_flag_eattr *ea;
u32 mask = 1;
for(; mask != 0; mask <<= 1) {
if (mask & ext2) {
ea = get_by_ext2(mask);
if (ea == NULL)
return -EINVAL;
*gfs2 |= ea->flag;
}
}
return 0;
}
static int get_ext2_flags(struct inode *inode, u32 __user *ptr)
{
struct gfs2_inode *ip = inode->u.generic_ip;
struct gfs2_holder gh;
int error;
u32 ext2;
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
error = gfs2_glock_nq_m_atime(1, &gh);
if (error)
return error;
ext2 = gfs2_flags_to_ext2(ip->i_di.di_flags);
if (put_user(ext2, ptr))
error = -EFAULT;
gfs2_glock_dq_m(1, &gh);
gfs2_holder_uninit(&gh);
return error;
}
/* Flags that can be set by user space */
#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \
GFS2_DIF_DIRECTIO| \
GFS2_DIF_IMMUTABLE| \
GFS2_DIF_APPENDONLY| \
GFS2_DIF_NOATIME| \
GFS2_DIF_SYNC| \
GFS2_DIF_SYSTEM| \
GFS2_DIF_INHERIT_DIRECTIO| \
GFS2_DIF_INHERIT_JDATA)
/**
* gfs2_set_flags - set flags on an inode
* @inode: The inode
* @flags: The flags to set
* @mask: Indicates which flags are valid
*
*/
static int gfs2_set_flags(struct inode *inode, u32 flags, u32 mask)
{
struct gfs2_inode *ip = inode->u.generic_ip;
struct buffer_head *bh;
struct gfs2_holder gh;
int error;
u32 new_flags;
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (error)
return error;
new_flags = (ip->i_di.di_flags & ~mask) | (flags & mask);
if ((new_flags ^ flags) == 0)
goto out;
error = -EINVAL;
if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET)
goto out;
if (S_ISDIR(inode->i_mode)) {
if ((new_flags ^ flags) & (GFS2_DIF_JDATA | GFS2_DIF_DIRECTIO))
goto out;
} else if (S_ISREG(inode->i_mode)) {
if ((new_flags ^ flags) & (GFS2_DIF_INHERIT_DIRECTIO|
GFS2_DIF_INHERIT_JDATA))
goto out;
} else
goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE))
goto out;
if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY))
goto out;
error = gfs2_repermission(inode, MAY_WRITE, NULL);
if (error)
goto out;
error = gfs2_meta_inode_buffer(ip, &bh);
if (error)
goto out;
gfs2_trans_add_bh(ip->i_gl, bh, 1);
ip->i_di.di_flags = new_flags;
gfs2_dinode_out(&ip->i_di, bh->b_data);
brelse(bh);
out:
gfs2_glock_dq_uninit(&gh);
return error;
}
static int set_ext2_flags(struct inode *inode, u32 __user *ptr)
{
u32 ext2, gfs2;
if (get_user(ext2, ptr))
return -EFAULT;
if (gfs2_flags_from_ext2(&gfs2, ext2))
return -EINVAL;
return gfs2_set_flags(inode, gfs2, ~0);
}
int gfs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
case EXT2_IOC_GETFLAGS:
return get_ext2_flags(inode, (u32 __user *)arg);
case EXT2_IOC_SETFLAGS:
return set_ext2_flags(inode, (u32 __user *)arg);
}
return -ENOTTY;
}
/** /**
* gfs2_mmap - * gfs2_mmap -
* @file: The file to map * @file: The file to map
...@@ -832,6 +1041,7 @@ struct file_operations gfs2_file_fops = { ...@@ -832,6 +1041,7 @@ struct file_operations gfs2_file_fops = {
.write = generic_file_write, .write = generic_file_write,
.writev = generic_file_writev, .writev = generic_file_writev,
.aio_write = generic_file_aio_write, .aio_write = generic_file_aio_write,
.ioctl = gfs2_ioctl,
.mmap = gfs2_mmap, .mmap = gfs2_mmap,
.open = gfs2_open, .open = gfs2_open,
.release = gfs2_close, .release = gfs2_close,
...@@ -843,6 +1053,7 @@ struct file_operations gfs2_file_fops = { ...@@ -843,6 +1053,7 @@ struct file_operations gfs2_file_fops = {
struct file_operations gfs2_dir_fops = { struct file_operations gfs2_dir_fops = {
.readdir = gfs2_readdir, .readdir = gfs2_readdir,
.ioctl = gfs2_ioctl,
.open = gfs2_open, .open = gfs2_open,
.release = gfs2_close, .release = gfs2_close,
.fsync = gfs2_fsync, .fsync = gfs2_fsync,
......
...@@ -97,9 +97,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -97,9 +97,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
INIT_LIST_HEAD(&sdp->sd_log_le_rg); INIT_LIST_HEAD(&sdp->sd_log_le_rg);
INIT_LIST_HEAD(&sdp->sd_log_le_databuf); INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
INIT_LIST_HEAD(&sdp->sd_log_blks_list); mutex_init(&sdp->sd_log_reserve_mutex);
init_waitqueue_head(&sdp->sd_log_blks_wait);
INIT_LIST_HEAD(&sdp->sd_ail1_list); INIT_LIST_HEAD(&sdp->sd_ail1_list);
INIT_LIST_HEAD(&sdp->sd_ail2_list); INIT_LIST_HEAD(&sdp->sd_ail2_list);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -417,18 +418,16 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -417,18 +418,16 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (!gfs2_assert_withdraw(sdp, !error)) { if (!gfs2_assert_withdraw(sdp, !error)) {
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
struct qstr str = { .name = ".", .len = 1 }; struct qstr str;
str.hash = gfs2_disk_hash(str.name, str.len);
gfs2_str2qstr(&str, ".");
gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent); gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
dent->de_inum = di->di_num; /* already GFS2 endian */ dent->de_inum = di->di_num; /* already GFS2 endian */
dent->de_type = DT_DIR; dent->de_type = DT_DIR;
di->di_entries = cpu_to_be32(1); di->di_entries = cpu_to_be32(1);
str.name = ".."; gfs2_str2qstr(&str, "..");
str.len = 2;
str.hash = gfs2_disk_hash(str.name, str.len);
dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
...@@ -772,9 +771,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -772,9 +771,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (dir_rename) { if (dir_rename) {
struct qstr name; struct qstr name;
name.len = 2; gfs2_str2qstr(&name, "..");
name.name = "..";
name.hash = gfs2_disk_hash(name.name, name.len);
error = gfs2_change_nlink(ndip, +1); error = gfs2_change_nlink(ndip, +1);
if (error) if (error)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "gfs2.h" #include "gfs2.h"
...@@ -27,6 +28,7 @@ ...@@ -27,6 +28,7 @@
#include "recovery.h" #include "recovery.h"
#include "super.h" #include "super.h"
#include "util.h" #include "util.h"
#include "dir.h"
int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
struct buffer_head **bh) struct buffer_head **bh)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/crc32.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
......
...@@ -28,11 +28,6 @@ kmem_cache_t *gfs2_glock_cachep __read_mostly; ...@@ -28,11 +28,6 @@ kmem_cache_t *gfs2_glock_cachep __read_mostly;
kmem_cache_t *gfs2_inode_cachep __read_mostly; kmem_cache_t *gfs2_inode_cachep __read_mostly;
kmem_cache_t *gfs2_bufdata_cachep __read_mostly; kmem_cache_t *gfs2_bufdata_cachep __read_mostly;
uint32_t gfs2_disk_hash(const char *data, int len)
{
return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF;
}
void gfs2_assert_i(struct gfs2_sbd *sdp) void gfs2_assert_i(struct gfs2_sbd *sdp)
{ {
printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n", printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n",
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
#ifndef __UTIL_DOT_H__ #ifndef __UTIL_DOT_H__
#define __UTIL_DOT_H__ #define __UTIL_DOT_H__
uint32_t gfs2_disk_hash(const char *data, int len);
#define fs_printk(level, fs, fmt, arg...) \ #define fs_printk(level, fs, fmt, arg...) \
printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg) printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册