summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorAlek Du <alek.du@intel.com>2010-02-22 15:09:12 +0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-23 11:39:59 -0800
commit2e236fea2b554b7b72f66d96ceae9e3fa4da675a (patch)
tree500ab7afe7f55a0777c572865d708a5cf7f00ae2 /core
parent2ae68967b8c938c5b936cc01f38af22590a6b8fd (diff)
downloadsyslinux-2e236fea2b554b7b72f66d96ceae9e3fa4da675a.tar.gz
pathbased:btrfs use iget interface and leverage general search routing
Now btrfs won't export its own searchdir, it uses the iget and iget_root interface. Signed-off-by: Alek Du <alek.du@intel.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'core')
-rw-r--r--core/fs/btrfs/btrfs.c255
-rw-r--r--core/fs/btrfs/btrfs.h1
2 files changed, 81 insertions, 175 deletions
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
index 4389302f..5a53c2c7 100644
--- a/core/fs/btrfs/btrfs.c
+++ b/core/fs/btrfs/btrfs.c
@@ -17,6 +17,7 @@
#include <core.h>
#include <disk.h>
#include <fs.h>
+#include <sys/stat.h>
#include "btrfs.h"
/* compare function used for bin_search */
@@ -53,13 +54,6 @@ static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func,
return 1;
}
-struct open_file_t {
- u64 devid; /* always 1 if allocated, reserved for multi disks */
- u64 bytenr; /* start offset in devid */
- u64 pos; /* current offset in file */
-};
-
-static struct open_file_t Files[MAX_OPEN];
static int cache_ready;
static struct fs_info *fs;
static struct btrfs_chunk_map chunk_map;
@@ -431,195 +425,105 @@ static inline u64 btrfs_name_hash(const char *name, int len)
return btrfs_crc32c((u32)~1, name, len);
}
-/* search a file with full path or relative path */
-static int btrfs_search_fs_tree(const char *fpath, u64 *offset,
- u64 *size, u8 *type)
+static inline int get_inode_mode(int mode)
{
- char name[256];
- char *tmp = name;
- /* this can be used as cwd during the file searching */
- static u64 objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
- static u8 level; /* dir level */
- static u64 objs[16]; /* history for ../ operation */
- int ret;
+ if (S_ISLNK(mode))
+ return I_SYMLINK;
+ if (S_ISDIR(mode))
+ return I_DIR;
+ return I_FILE;
+}
+
+static struct inode *btrfs_iget_by_inr(struct fs_info *fs, u64 inr)
+{
+ struct inode *inode;
+ struct btrfs_inode_item inode_item;
struct btrfs_disk_key search_key;
struct btrfs_path path;
- struct btrfs_dir_item dir_item;
- struct btrfs_inode_item inode_item;
- struct btrfs_file_extent_item extent_item;
-
- if (*fpath == '/' || *fpath == '\0') { /* full or null path */
- objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
- level = 0;
- objs[level] = objectid;
- }
- *tmp = '\0';
- while (1) {
- char c = *(fpath++);
-
- *(tmp++) = c;
- if (!c)
- break;
- if (c == '/') {
- *(tmp-1) = '\0';
- if (!strcmp(name, "..")) {
- if (level)
- level--;
- objectid = objs[level];
- } else if (strlen(name) && strcmp(name, ".")) {
- /* a "real" dir */
- search_key.objectid = objectid;
- search_key.type = BTRFS_DIR_ITEM_KEY;
- search_key.offset =
- btrfs_name_hash(name, strlen(name));
- clear_path(&path);
- ret = search_tree(fs_tree, &search_key, &path);
- if (ret)
- return ret; /* not found */
- dir_item = *(struct btrfs_dir_item *)path.data;
- /* found the name but it is not a dir ? */
- if (dir_item.type != BTRFS_FT_DIR) {
- printf("%s is not a dir\n", name);
- return -1;
- }
- objectid = dir_item.location.objectid;
- level++;
- if (level >= 16) {
- printf("too many dir levels(>16)\n");
- return -1;
- }
- objs[level] = objectid;
- }
- tmp = name;
- *tmp = '\0';
- }
- }
- /* get file dir_item */
- if (!strlen(name))/* no file part */
- return -1;
- search_key.objectid = objectid;
- search_key.type = BTRFS_DIR_ITEM_KEY;
- search_key.offset = btrfs_name_hash(name, strlen(name));
- clear_path(&path);
- ret = search_tree(fs_tree, &search_key, &path);
- if (ret)
- return ret; /* not found */
- dir_item = *(struct btrfs_dir_item *)path.data;
- *type = dir_item.type;
- /* found the name but it is not a file ? */
- if (*type != BTRFS_FT_REG_FILE && *type != BTRFS_FT_SYMLINK) {
- printf("%s is not a file\n", name);
- return -1;
- }
-
- /* get inode */
- search_key = dir_item.location;
- clear_path(&path);
- ret = search_tree(fs_tree, &search_key, &path);
- if (ret)
- return ret; /* not found */
- inode_item = *(struct btrfs_inode_item *)path.data;
+ int ret;
- /* get file_extent_item */
- search_key.objectid = dir_item.location.objectid;
- search_key.type = BTRFS_EXTENT_DATA_KEY;
+ /* FIXME: some BTRFS inode member are u64, while our logical inode
+ is u32, we may need change them to u64 later */
+ search_key.objectid = inr;
+ search_key.type = BTRFS_INODE_ITEM_KEY;
search_key.offset = 0;
clear_path(&path);
ret = search_tree(fs_tree, &search_key, &path);
if (ret)
- return ret; /* not found */
- extent_item = *(struct btrfs_file_extent_item *)path.data;
- *size = inode_item.size;
- if (extent_item.type == BTRFS_FILE_EXTENT_INLINE)/* inline file */
- *offset = path.offsets[0] + sizeof(struct btrfs_header)
- + path.item.offset
- + offsetof(struct btrfs_file_extent_item, disk_bytenr);
- else
- *offset = extent_item.disk_bytenr;
-
- return 0;
-}
-
-static struct open_file_t *alloc_file(void)
-{
- struct open_file_t *file = Files;
- int i;
-
- for (i = 0; i < MAX_OPEN; i++) {
- if (file->devid == 0) /* found it */
- return file;
- file++;
- }
-
- return NULL; /* not found */
+ return NULL;
+ inode_item = *(struct btrfs_inode_item *)path.data;
+ if (!(inode = alloc_inode(fs, inr, sizeof(u64))))
+ return NULL;
+ inode->ino = inr;
+ inode->size = inode_item.size;
+ inode->mode = get_inode_mode(inode_item.mode);
+
+ if (inode->mode == I_FILE) {
+ struct btrfs_file_extent_item extent_item;
+ u64 offset;
+
+ /* get file_extent_item */
+ search_key.type = BTRFS_EXTENT_DATA_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ ret = search_tree(fs_tree, &search_key, &path);
+ if (ret)
+ return NULL; /* impossible */
+ extent_item = *(struct btrfs_file_extent_item *)path.data;
+ if (extent_item.type == BTRFS_FILE_EXTENT_INLINE)/* inline file */
+ offset = path.offsets[0] + sizeof(struct btrfs_header)
+ + path.item.offset
+ + offsetof(struct btrfs_file_extent_item, disk_bytenr);
+ else
+ offset = extent_item.disk_bytenr;
+ *(u64 *)inode->pvt = offset;
+ }
+ return inode;
}
-static inline void close_pvt(struct open_file_t *of)
+static struct inode *btrfs_iget_root(struct fs_info *fs)
{
- of->devid = 0;
+ /* BTRFS_FIRST_CHUNK_TREE_OBJECTID(256) actually is first OBJECTID for FS_TREE */
+ return btrfs_iget_by_inr(fs, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
}
-static void btrfs_close_file(struct file *file)
+static struct inode *btrfs_iget(char *name, struct inode *parent)
{
- close_pvt(file->open_file);
-}
+ struct fs_info *fs = parent->fs;
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ struct btrfs_dir_item dir_item;
+ int ret;
-/* set the cwd to the global Path in patcharea */
-static void btrfs_set_cwd(void)
-{
- u64 tmp;
- char path[FILENAME_MAX];
+ search_key.objectid = parent->ino;
+ search_key.type = BTRFS_DIR_ITEM_KEY;
+ search_key.offset = btrfs_name_hash(name, strlen(name));
+ clear_path(&path);
+ ret = search_tree(fs_tree, &search_key, &path);
+ if (ret)
+ return NULL;
+ dir_item = *(struct btrfs_dir_item *)path.data;
- sprintf(path, "%s/", CurrentDirName);
- btrfs_search_fs_tree(path, &tmp, &tmp, (u8 *)&tmp);
+ return btrfs_iget_by_inr(fs, dir_item.location.objectid);
}
-static void btrfs_searchdir(char *filename, struct file *file)
+static int btrfs_readlink(struct inode *inode, char *buf)
{
- struct open_file_t *open_file;
- u64 offset, size;
- char name[FILENAME_MAX];
- char *fname = filename;
- u8 type;
- int ret;
-
- file->open_file = NULL;
- file->file_len = 0;
- do {
- ret = btrfs_search_fs_tree(fname, &offset, &size, &type);
- if (ret)
- break;
- if (type == BTRFS_FT_SYMLINK) {
- btrfs_read(name, logical_physical(offset), size);
- name[size] = '\0';
- fname = name;
- continue;
- }
- open_file = alloc_file();
- file->open_file = (void *)open_file;
- if (open_file) {
- /* we may support multi devices later on */
- open_file->devid = 1;
- open_file->bytenr = offset;
- open_file->pos = 0;
- file->file_len = size;
- }
- break;
- } while (1);
- /* restore the cwd, since the above search may change dir */
- btrfs_set_cwd();
+ btrfs_read(buf, logical_physical(*(u64 *)inode->pvt), inode->size);
+ buf[inode->size] = '\0';
+ return inode->size;
}
-static uint32_t btrfs_getfssec(struct file *gfile, char *buf, int sectors,
+static uint32_t btrfs_getfssec(struct file *file, char *buf, int sectors,
bool *have_more)
{
+ struct inode *inode = file->inode;
struct disk *disk = fs->fs_dev->disk;
- struct open_file_t *file = gfile->open_file;
u32 sec_shift = fs->fs_dev->disk->sector_shift;
- u32 phy = logical_physical(file->bytenr + file->pos);
+ u32 phy = logical_physical(*(u64 *)inode->pvt + file->offset);
u32 sec = phy >> sec_shift;
u32 off = phy - (sec << sec_shift);
- u32 remain = gfile->file_len - file->pos;
+ u32 remain = file->file_len - file->offset;
u32 remain_sec = (remain + (1 << sec_shift) - 1) >> sec_shift;
u32 size;
@@ -630,7 +534,7 @@ static uint32_t btrfs_getfssec(struct file *gfile, char *buf, int sectors,
size = sectors << sec_shift;
if (size > remain)
size = remain;
- file->pos += size;
+ file->offset += size;
*have_more = remain - size;
if (off)/* inline file is not started with sector boundary */
@@ -707,22 +611,23 @@ static int btrfs_fs_init(struct fs_info *_fs)
btrfs_read_sys_chunk_array();
btrfs_read_chunk_tree();
btrfs_get_fs_tree();
- btrfs_set_cwd();
cache_ready = 1;
/* Initialize the block cache */
- cache_init(fs->fs_dev, fs->block_size);
+ cache_init(fs->fs_dev, fs->block_shift);
- return fs->block_size;
+ return fs->block_shift;
}
const struct fs_ops btrfs_fs_ops = {
.fs_name = "btrfs",
.fs_flags = 0,
.fs_init = btrfs_fs_init,
- .searchdir = btrfs_searchdir,
+ .iget_root = btrfs_iget_root,
+ .iget = btrfs_iget,
+ .readlink = btrfs_readlink,
.getfssec = btrfs_getfssec,
- .close_file = btrfs_close_file,
+ .close_file = generic_close_file,
.mangle_name = generic_mangle_name,
.unmangle_name = generic_unmangle_name,
.load_config = generic_load_config
diff --git a/core/fs/btrfs/btrfs.h b/core/fs/btrfs/btrfs.h
index eacdeb5f..68522271 100644
--- a/core/fs/btrfs/btrfs.h
+++ b/core/fs/btrfs/btrfs.h
@@ -39,6 +39,7 @@ typedef u64 __le64;
#define BTRFS_ROOT_ITEM_KEY 132
#define BTRFS_EXTENT_DATA_KEY 108
#define BTRFS_DIR_ITEM_KEY 84
+#define BTRFS_INODE_ITEM_KEY 1
#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
#define BTRFS_FS_TREE_OBJECTID 5ULL