|
@@ -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 @@ fail:
|
|
}
|
|
}
|
|
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
|
|
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,
|
|
* 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,
|
|
}
|
|
}
|
|
|
|
|
|
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 @@ error:
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
-static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode,
|
|
|
|
- void *buf,
|
|
|
|
- unsigned int len, gfs2_dscan_t scan,
|
|
|
|
- const struct qstr *name)
|
|
|
|
|
|
+static int gfs2_dirent_offset(const void *buf)
|
|
{
|
|
{
|
|
- struct gfs2_meta_header *h = buf;
|
|
|
|
- struct gfs2_dirent *dent, *prev;
|
|
|
|
- unsigned offset;
|
|
|
|
- unsigned size;
|
|
|
|
- int ret = 0;
|
|
|
|
|
|
+ const struct gfs2_meta_header *h = buf;
|
|
|
|
+ int offset;
|
|
|
|
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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);
|
|
|
|
- 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);
|
|
|
|
|
|
+ gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
|
|
*pbh = bh;
|
|
*pbh = bh;
|
|
return leaf;
|
|
return leaf;
|
|
}
|
|
}
|
|
@@ -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)
|
|
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)
|
|
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)
|
|
|
|
|
|
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,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * do_filldir_single - Read directory entries out of a single block
|
|
|
|
- * @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 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)
|
|
|
|
|
|
+static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
|
|
|
|
+ gfs2_filldir_t filldir, int *copied,
|
|
|
|
+ unsigned *depth, u64 leaf_no)
|
|
{
|
|
{
|
|
- struct gfs2_dirent **darr;
|
|
|
|
- struct gfs2_dirent *de;
|
|
|
|
- unsigned int e = 0;
|
|
|
|
- int error;
|
|
|
|
-
|
|
|
|
- if (!entries)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL);
|
|
|
|
- if (!darr)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ struct gfs2_inode *ip = inode->u.generic_ip;
|
|
|
|
+ struct buffer_head *bh;
|
|
|
|
+ struct gfs2_leaf *lf;
|
|
|
|
+ unsigned entries = 0;
|
|
|
|
+ unsigned leaves = 0;
|
|
|
|
+ const struct gfs2_dirent **darr, *dent;
|
|
|
|
+ struct dirent_gather g;
|
|
|
|
+ struct buffer_head **larr;
|
|
|
|
+ int leaf = 0;
|
|
|
|
+ int error, i;
|
|
|
|
+ u64 lfn = leaf_no;
|
|
|
|
|
|
- dirent_first(dip, bh, &de);
|
|
|
|
do {
|
|
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);
|
|
|
|
-
|
|
|
|
- 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);
|
|
|
|
|
|
+ error = get_leaf(ip, lfn, &bh);
|
|
if (error)
|
|
if (error)
|
|
- return error;
|
|
|
|
-
|
|
|
|
- leaf = (struct gfs2_leaf *)tmp_bh->b_data;
|
|
|
|
- if (leaf->lf_entries) {
|
|
|
|
- entries += be16_to_cpu(leaf->lf_entries);
|
|
|
|
- leaves++;
|
|
|
|
- }
|
|
|
|
- ln = be64_to_cpu(leaf->lf_next);
|
|
|
|
-
|
|
|
|
- brelse(tmp_bh);
|
|
|
|
- }
|
|
|
|
|
|
+ goto out;
|
|
|
|
+ lf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
+ if (leaves == 0)
|
|
|
|
+ *depth = be16_to_cpu(lf->lf_depth);
|
|
|
|
+ entries += be16_to_cpu(lf->lf_entries);
|
|
|
|
+ leaves++;
|
|
|
|
+ lfn = be64_to_cpu(lf->lf_next);
|
|
|
|
+ brelse(bh);
|
|
|
|
+ } while(lfn);
|
|
|
|
|
|
if (!entries)
|
|
if (!entries)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- if (leaves) {
|
|
|
|
- larr = kcalloc(leaves, sizeof(struct buffer_head *),GFP_KERNEL);
|
|
|
|
- if (!larr)
|
|
|
|
- return -ENOMEM;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL);
|
|
|
|
- if (!darr) {
|
|
|
|
- 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);
|
|
|
|
|
|
+ error = -ENOMEM;
|
|
|
|
+ larr = kmalloc((leaves + entries) * sizeof(void*), GFP_KERNEL);
|
|
|
|
+ if (!larr)
|
|
|
|
+ goto out;
|
|
|
|
+ darr = (const struct gfs2_dirent **)(larr + leaves);
|
|
|
|
+ g.pdent = darr;
|
|
|
|
+ g.offset = 0;
|
|
|
|
+ lfn = leaf_no;
|
|
|
|
|
|
- while (ln) {
|
|
|
|
- error = get_leaf(dip, ln, &tmp_bh);
|
|
|
|
|
|
+ do {
|
|
|
|
+ error = get_leaf(ip, lfn, &bh);
|
|
if (error)
|
|
if (error)
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- leaf = (struct gfs2_leaf *)tmp_bh->b_data;
|
|
|
|
- if (leaf->lf_entries) {
|
|
|
|
- dirent_first(dip, tmp_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, tmp_bh, &de) == 0);
|
|
|
|
-
|
|
|
|
- larr[l++] = tmp_bh;
|
|
|
|
-
|
|
|
|
- ln = be64_to_cpu(leaf->lf_next);
|
|
|
|
|
|
+ goto out_kfree;
|
|
|
|
+ lf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
+ lfn = be64_to_cpu(lf->lf_next);
|
|
|
|
+ if (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)) {
|
|
|
|
+ goto out_kfree;
|
|
|
|
+ }
|
|
|
|
+ error = 0;
|
|
|
|
+ larr[leaf++] = bh;
|
|
} else {
|
|
} else {
|
|
- ln = be64_to_cpu(leaf->lf_next);
|
|
|
|
- brelse(tmp_bh);
|
|
|
|
|
|
+ brelse(bh);
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ } while(lfn);
|
|
|
|
|
|
- if (gfs2_assert_withdraw(dip->i_sbd, l == leaves)) {
|
|
|
|
- error = -EIO;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- if (e != entries) {
|
|
|
|
- gfs2_consist_inode(dip);
|
|
|
|
- error = -EIO;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- error = do_filldir_main(dip, offset, opaque, filldir, darr,
|
|
|
|
|
|
+ error = do_filldir_main(ip, offset, opaque, filldir, darr,
|
|
entries, copied);
|
|
entries, copied);
|
|
-
|
|
|
|
- out:
|
|
|
|
- kfree(darr);
|
|
|
|
- for (x = 0; x < l; x++)
|
|
|
|
- brelse(larr[x]);
|
|
|
|
|
|
+out_kfree:
|
|
|
|
+ for(i = 0; i < leaf; i++)
|
|
|
|
+ brelse(larr[i]);
|
|
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,
|
|
* 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;
|
|
|
|
- struct gfs2_leaf *leaf;
|
|
|
|
- uint32_t hsize, len;
|
|
|
|
|
|
+ uint32_t hsize, len = 0;
|
|
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,
|
|
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;
|
|
|
|
-
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- 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,
|
|
|
|
- gfs2_filldir_t filldir)
|
|
|
|
|
|
+int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque,
|
|
|
|
+ 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,
|
|
|
|
- opaque, filldir,
|
|
|
|
- dibh, dip->i_di.di_entries,
|
|
|
|
- &copied);
|
|
|
|
|
|
+ error = -ENOMEM;
|
|
|
|
+ darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
+ 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)
|
|
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)
|
|
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
|