buffer extent for performance

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-12-02 15:28:29 +01:00
parent 8006f6779e
commit a43c4bc55f

View file

@ -70,6 +70,8 @@ struct grub_btrfs_data
unsigned int sblock_number; unsigned int sblock_number;
grub_uint64_t tree; grub_uint64_t tree;
grub_uint64_t inode; grub_uint64_t inode;
grub_uint64_t extstart;
struct grub_btrfs_extent_data *extent;
}; };
struct grub_btrfs_key struct grub_btrfs_key
@ -557,7 +559,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
static struct grub_btrfs_data * static struct grub_btrfs_data *
grub_btrfs_mount (grub_disk_t disk) grub_btrfs_mount (grub_disk_t disk)
{ {
struct grub_btrfs_data *data = grub_malloc (sizeof (*data)); struct grub_btrfs_data *data = grub_zalloc (sizeof (*data));
unsigned i; unsigned i;
grub_err_t err = GRUB_ERR_NONE; grub_err_t err = GRUB_ERR_NONE;
@ -899,7 +901,10 @@ grub_btrfs_open (struct grub_file *file, const char *name)
static grub_err_t static grub_err_t
grub_btrfs_close (grub_file_t file) grub_btrfs_close (grub_file_t file)
{ {
grub_free (file->data); struct grub_btrfs_data *data = file->data;
grub_free (data->extent);
grub_free (data);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
@ -909,65 +914,63 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
{ {
struct grub_btrfs_data *data = file->data; struct grub_btrfs_data *data = file->data;
grub_off_t pos = file->offset; grub_off_t pos = file->offset;
grub_disk_addr_t elemaddr;
grub_size_t elemsize;
struct grub_btrfs_key key_in, key_out;
grub_off_t extoff;
while (len) while (len)
{ {
grub_size_t csize; grub_size_t csize;
struct grub_btrfs_extent_data *extent;
grub_err_t err; grub_err_t err;
key_in.object_id = data->inode; grub_off_t extoff;
key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; if (!data->extent || data->extstart > pos ||
key_in.offset = grub_cpu_to_le64 (pos); grub_le_to_cpu64 (data->extent->size) + data->extstart <= pos)
err = lower_bound (data, file->device->disk, &key_in, &key_out,
data->tree,
&elemaddr, &elemsize, NULL);
if (err)
return -1;
if (key_out.object_id != data->inode
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
{ {
grub_error (GRUB_ERR_BAD_FS, "extent not found"); struct grub_btrfs_key key_in, key_out;
return -1; grub_disk_addr_t elemaddr;
} grub_size_t elemsize;
extent = grub_malloc (elemsize); grub_free (data->extent);
if (!extent) key_in.object_id = data->inode;
return grub_errno; key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM;
key_in.offset = grub_cpu_to_le64 (pos);
err = lower_bound (data, file->device->disk, &key_in, &key_out,
data->tree,
&elemaddr, &elemsize, NULL);
if (err)
return -1;
if (key_out.object_id != data->inode
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
{
grub_error (GRUB_ERR_BAD_FS, "extent not found");
return -1;
}
data->extstart = grub_le_to_cpu64 (key_out.offset);
data->extent = grub_malloc (elemsize);
if (!data->extent)
return grub_errno;
err = grub_btrfs_read_logical (data, file->device->disk, elemaddr, err = grub_btrfs_read_logical (data, file->device->disk, elemaddr,
extent, elemsize); data->extent, elemsize);
if (err) if (err)
{ return err;
grub_free (extent); if (grub_le_to_cpu64 (data->extent->size) + data->extstart <= pos)
return err; return grub_error (GRUB_ERR_BAD_FS, "extent not found");
grub_dprintf ("btrfs", "extent 0x%" PRIxGRUB_UINT64_T "+0x%"
PRIxGRUB_UINT64_T "\n",
grub_le_to_cpu64 (key_out.offset),
grub_le_to_cpu64 (data->extent->size));
} }
if (grub_le_to_cpu64 (extent->size) + grub_le_to_cpu64 (key_out.offset) csize = grub_le_to_cpu64 (data->extent->size)
<= pos) + grub_le_to_cpu64 (data->extstart) - pos;
{ extoff = pos - data->extstart;
grub_free (extent);
return grub_error (GRUB_ERR_BAD_FS, "extent not found");
}
grub_dprintf ("btrfs", "extent 0x%" PRIxGRUB_UINT64_T "+0x%"
PRIxGRUB_UINT64_T "\n",
grub_le_to_cpu64 (key_out.offset),
grub_le_to_cpu64 (extent->size));
csize = grub_le_to_cpu64 (extent->size)
+ grub_le_to_cpu64 (key_out.offset) - pos;
extoff = pos - grub_le_to_cpu64 (key_out.offset);
if (csize > len) if (csize > len)
csize = len; csize = len;
if (extent->encryption) if (data->extent->encryption)
{ {
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"encryption not supported"); "encryption not supported");
return -1; return -1;
} }
if (extent->compression) if (data->extent->compression)
{ {
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"compression not supported"); "compression not supported");
@ -975,37 +978,34 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
} }
if (extent->encoding) if (data->extent->encoding)
{ {
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"encoding not supported"); "encoding not supported");
return -1; return -1;
} }
switch (extent->type) switch (data->extent->type)
{ {
case GRUB_BTRFS_EXTENT_INLINE: case GRUB_BTRFS_EXTENT_INLINE:
grub_memcpy (buf, extent->inl + extoff, csize); grub_memcpy (buf, data->extent->inl + extoff, csize);
grub_free (extent);
break; break;
case GRUB_BTRFS_EXTENT_REGULAR: case GRUB_BTRFS_EXTENT_REGULAR:
if (!extent->laddr) if (!data->extent->laddr)
{ {
grub_memset (buf, 0, csize); grub_memset (buf, 0, csize);
break; break;
} }
err = grub_btrfs_read_logical (data, file->device->disk, err = grub_btrfs_read_logical (data, file->device->disk,
grub_le_to_cpu64 (extent->laddr) grub_le_to_cpu64 (data->extent->laddr)
+ extoff, + extoff,
buf, csize); buf, csize);
grub_free (extent);
if (err) if (err)
return -1; return -1;
break; break;
default: default:
grub_free (extent);
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported extent type 0x%x", extent->type); "unsupported extent type 0x%x", data->extent->type);
return -1; return -1;
} }
buf += csize; buf += csize;