From: Anas Nashif Date: Sat, 10 Nov 2012 16:33:31 +0000 (-0800) Subject: libext2fs X-Git-Tag: accepted/trunk/20121221.213755~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=42bfad443ff55c8542548208c4b3f363ffa4b584;p=platform%2Fupstream%2Fsyslinux.git libext2fs --- diff --git a/libinstaller/linuxioctl.h b/libinstaller/linuxioctl.h index 7ef919a..100fd86 100644 --- a/libinstaller/linuxioctl.h +++ b/libinstaller/linuxioctl.h @@ -19,7 +19,7 @@ #undef SECTOR_SIZE /* Defined in msdos_fs.h for no good reason */ #undef SECTOR_BITS -#include /* EXT2_IOC_* */ +#include /* EXT2_IOC_* */ #ifndef FAT_IOCTL_GET_ATTRIBUTES # define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32) diff --git a/packaging/0001-btrfs-Correctly-determine-the-installation-subvolume.patch b/packaging/0001-btrfs-Correctly-determine-the-installation-subvolume.patch index e69de29..c5c941f 100644 --- a/packaging/0001-btrfs-Correctly-determine-the-installation-subvolume.patch +++ b/packaging/0001-btrfs-Correctly-determine-the-installation-subvolume.patch @@ -0,0 +1,493 @@ +From c46d7f1567870b9a2bb0a946af741a585e96fe67 Mon Sep 17 00:00:00 2001 +From: Yi Yang +Date: Tue, 12 Jul 2011 14:53:50 +0800 +Subject: [PATCH] btrfs: Correctly determine the installation subvolume + +There are multiple ways to set up subvolumes in btrfs. Use a general +determination method which works for all schemes. + +Signed-off-by: H. Peter Anvin +--- + extlinux/btrfs.h | 105 +++++++++++++++++++ + extlinux/main.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 376 insertions(+), 32 deletions(-) + +diff --git a/extlinux/btrfs.h b/extlinux/btrfs.h +index 39a861a..be0c24e 100644 +--- a/extlinux/btrfs.h ++++ b/extlinux/btrfs.h +@@ -1,6 +1,9 @@ + #ifndef _BTRFS_H_ + #define _BTRFS_H_ + ++#include ++#include ++ + #define BTRFS_SUPER_MAGIC 0x9123683E + #define BTRFS_SUPER_INFO_OFFSET (64 * 1024) + #define BTRFS_SUPER_INFO_SIZE 4096 +@@ -8,6 +11,40 @@ + #define BTRFS_CSUM_SIZE 32 + #define BTRFS_FSID_SIZE 16 + ++typedef __u64 u64; ++typedef __u32 u32; ++typedef __u16 u16; ++typedef __u8 u8; ++typedef u64 __le64; ++typedef u16 __le16; ++ ++#define BTRFS_ROOT_BACKREF_KEY 144 ++#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL ++#define BTRFS_DIR_ITEM_KEY 84 ++ ++/* ++ * * this is used for both forward and backward root refs ++ * */ ++struct btrfs_root_ref { ++ __le64 dirid; ++ __le64 sequence; ++ __le16 name_len; ++} __attribute__ ((__packed__)); ++ ++struct btrfs_disk_key { ++ __le64 objectid; ++ u8 type; ++ __le64 offset; ++} __attribute__ ((__packed__)); ++ ++struct btrfs_dir_item { ++ struct btrfs_disk_key location; ++ __le64 transid; ++ __le16 data_len; ++ __le16 name_len; ++ u8 type; ++} __attribute__ ((__packed__)); ++ + struct btrfs_super_block { + unsigned char csum[BTRFS_CSUM_SIZE]; + /* the first 3 fields must match struct btrfs_header */ +@@ -19,4 +56,72 @@ struct btrfs_super_block { + u64 magic; + } __attribute__ ((__packed__)); + ++ ++#define BTRFS_IOCTL_MAGIC 0x94 ++#define BTRFS_VOL_NAME_MAX 255 ++#define BTRFS_PATH_NAME_MAX 4087 ++ ++struct btrfs_ioctl_vol_args { ++ __s64 fd; ++ char name[BTRFS_PATH_NAME_MAX + 1]; ++}; ++ ++struct btrfs_ioctl_search_key { ++ /* which root are we searching. 0 is the tree of tree roots */ ++ __u64 tree_id; ++ ++ /* keys returned will be >= min and <= max */ ++ __u64 min_objectid; ++ __u64 max_objectid; ++ ++ /* keys returned will be >= min and <= max */ ++ __u64 min_offset; ++ __u64 max_offset; ++ ++ /* max and min transids to search for */ ++ __u64 min_transid; ++ __u64 max_transid; ++ ++ /* keys returned will be >= min and <= max */ ++ __u32 min_type; ++ __u32 max_type; ++ ++ /* ++ * how many items did userland ask for, and how many are we ++ * returning ++ */ ++ __u32 nr_items; ++ ++ /* align to 64 bits */ ++ __u32 unused; ++ ++ /* some extra for later */ ++ __u64 unused1; ++ __u64 unused2; ++ __u64 unused3; ++ __u64 unused4; ++}; ++ ++struct btrfs_ioctl_search_header { ++ __u64 transid; ++ __u64 objectid; ++ __u64 offset; ++ __u32 type; ++ __u32 len; ++} __attribute__((may_alias)); ++ ++#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) ++/* ++ * the buf is an array of search headers where ++ * each header is followed by the actual item ++ * the type field is expanded to 32 bits for alignment ++ */ ++struct btrfs_ioctl_search_args { ++ struct btrfs_ioctl_search_key key; ++ char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; ++}; ++ ++#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ ++ struct btrfs_ioctl_search_args) ++ + #endif +diff --git a/extlinux/main.c b/extlinux/main.c +index e5212a9..201fb02 100755 +--- a/extlinux/main.c ++++ b/extlinux/main.c +@@ -20,12 +20,12 @@ + #define _GNU_SOURCE /* Enable everything */ + #include + /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */ +-typedef uint64_t u64; + #include + #include + #include + #include + #include ++#include + #ifndef __KLIBC__ + #include + #endif +@@ -65,7 +65,6 @@ typedef uint64_t u64; + boot image, the boot sector is from 0~512, the boot image starts after */ + #define BTRFS_BOOTSECT_AREA 65536 + #define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE +-#define BTRFS_SUBVOL_OPT "subvol=" + #define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */ + static char subvol[BTRFS_SUBVOL_MAX]; + +@@ -494,6 +493,270 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst) + return 0; + } + ++/* ++ * * test if path is a subvolume: ++ * * this function return ++ * * 0-> path exists but it is not a subvolume ++ * * 1-> path exists and it is a subvolume ++ * * -1 -> path is unaccessible ++ * */ ++static int test_issubvolume(char *path) ++{ ++ ++ struct stat st; ++ int res; ++ ++ res = stat(path, &st); ++ if(res < 0 ) ++ return -1; ++ ++ return (st.st_ino == 256) && S_ISDIR(st.st_mode); ++ ++} ++ ++/* ++ * Get file handle for a file or dir ++ */ ++static int open_file_or_dir(const char *fname) ++{ ++ int ret; ++ struct stat st; ++ DIR *dirstream; ++ int fd; ++ ++ ret = stat(fname, &st); ++ if (ret < 0) { ++ return -1; ++ } ++ if (S_ISDIR(st.st_mode)) { ++ dirstream = opendir(fname); ++ if (!dirstream) { ++ return -2; ++ } ++ fd = dirfd(dirstream); ++ } else { ++ fd = open(fname, O_RDWR); ++ } ++ if (fd < 0) { ++ return -3; ++ } ++ return fd; ++} ++ ++/* ++ * Get the default subvolume of a btrfs filesystem ++ * rootdir: btrfs root dir ++ * subvol: this function will save the default subvolume name here ++ */ ++static char * get_default_subvol(char * rootdir, char * subvol) ++{ ++ struct btrfs_ioctl_search_args args; ++ struct btrfs_ioctl_search_key *sk = &args.key; ++ struct btrfs_ioctl_search_header *sh; ++ int ret, i; ++ int fd; ++ struct btrfs_root_ref *ref; ++ struct btrfs_dir_item *dir_item; ++ unsigned long off = 0; ++ int name_len; ++ char *name; ++ u64 dir_id; ++ char dirname[4096]; ++ u64 defaultsubvolid = 0; ++ ++ ret = test_issubvolume(rootdir); ++ if (ret == 1) { ++ fd = open_file_or_dir(rootdir); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: failed to open %s\n", rootdir); ++ } ++ ret = fd; ++ } ++ if (ret <= 0) { ++ subvol[0] = '\0'; ++ return NULL; ++ } ++ ++ memset(&args, 0, sizeof(args)); ++ ++ /* search in the tree of tree roots */ ++ sk->tree_id = 1; ++ ++ /* ++ * set the min and max to backref keys. The search will ++ * only send back this type of key now. ++ */ ++ sk->max_type = BTRFS_DIR_ITEM_KEY; ++ sk->min_type = BTRFS_DIR_ITEM_KEY; ++ ++ /* ++ * set all the other params to the max, we'll take any objectid ++ * and any trans ++ */ ++ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; ++ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; ++ ++ sk->max_offset = (u64)-1; ++ sk->min_offset = 0; ++ sk->max_transid = (u64)-1; ++ ++ /* just a big number, doesn't matter much */ ++ sk->nr_items = 4096; ++ ++ while(1) { ++ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ if (ret < 0) { ++ fprintf(stderr, "ERROR: can't perform the search\n"); ++ subvol[0] = '\0'; ++ return NULL; ++ } ++ /* the ioctl returns the number of item it found in nr_items */ ++ if (sk->nr_items == 0) { ++ break; ++ } ++ ++ off = 0; ++ ++ /* ++ * for each item, pull the key out of the header and then ++ * read the root_ref item it contains ++ */ ++ for (i = 0; i < sk->nr_items; i++) { ++ sh = (struct btrfs_ioctl_search_header *)(args.buf + off); ++ off += sizeof(*sh); ++ if (sh->type == BTRFS_DIR_ITEM_KEY) { ++ dir_item = (struct btrfs_dir_item *)(args.buf + off); ++ name_len = dir_item->name_len; ++ name = (char *)(dir_item + 1); ++ ++ ++ /*add_root(&root_lookup, sh->objectid, sh->offset, ++ dir_id, name, name_len);*/ ++ strncpy(dirname, name, name_len); ++ dirname[name_len] = '\0'; ++ if (strcmp(dirname, "default") == 0) { ++ defaultsubvolid = dir_item->location.objectid; ++ break; ++ } ++ } ++ off += sh->len; ++ ++ /* ++ * record the mins in sk so we can make sure the ++ * next search doesn't repeat this root ++ */ ++ sk->min_objectid = sh->objectid; ++ sk->min_type = sh->type; ++ sk->max_type = sh->type; ++ sk->min_offset = sh->offset; ++ } ++ if (defaultsubvolid != 0) ++ break; ++ sk->nr_items = 4096; ++ /* this iteration is done, step forward one root for the next ++ * ioctl ++ */ ++ if (sk->min_objectid < (u64)-1) { ++ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; ++ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; ++ sk->max_type = BTRFS_ROOT_BACKREF_KEY; ++ sk->min_type = BTRFS_ROOT_BACKREF_KEY; ++ sk->min_offset = 0; ++ } else ++ break; ++ } ++ ++ if (defaultsubvolid == 0) { ++ subvol[0] = '\0'; ++ return NULL; ++ } ++ ++ memset(&args, 0, sizeof(args)); ++ ++ /* search in the tree of tree roots */ ++ sk->tree_id = 1; ++ ++ /* ++ * set the min and max to backref keys. The search will ++ * only send back this type of key now. ++ */ ++ sk->max_type = BTRFS_ROOT_BACKREF_KEY; ++ sk->min_type = BTRFS_ROOT_BACKREF_KEY; ++ ++ /* ++ * set all the other params to the max, we'll take any objectid ++ * and any trans ++ */ ++ sk->max_objectid = (u64)-1; ++ sk->max_offset = (u64)-1; ++ sk->max_transid = (u64)-1; ++ ++ /* just a big number, doesn't matter much */ ++ sk->nr_items = 4096; ++ ++ while(1) { ++ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ if (ret < 0) { ++ fprintf(stderr, "ERROR: can't perform the search\n"); ++ subvol[0] = '\0'; ++ return NULL; ++ } ++ /* the ioctl returns the number of item it found in nr_items */ ++ if (sk->nr_items == 0) ++ break; ++ ++ off = 0; ++ ++ /* ++ * for each item, pull the key out of the header and then ++ * read the root_ref item it contains ++ */ ++ for (i = 0; i < sk->nr_items; i++) { ++ sh = (struct btrfs_ioctl_search_header *)(args.buf + off); ++ off += sizeof(*sh); ++ if (sh->type == BTRFS_ROOT_BACKREF_KEY) { ++ ref = (struct btrfs_root_ref *)(args.buf + off); ++ name_len = ref->name_len; ++ name = (char *)(ref + 1); ++ dir_id = ref->dirid; ++ ++ /*add_root(&root_lookup, sh->objectid, sh->offset, ++ dir_id, name, name_len);*/ ++ if (sh->objectid == defaultsubvolid) { ++ strncpy(subvol, name, name_len); ++ subvol[name_len] = '\0'; ++ dprintf("The default subvolume: %s, ID: %llu\n", subvol, sh->objectid); ++ break; ++ } ++ ++ } ++ ++ off += sh->len; ++ ++ /* ++ * record the mins in sk so we can make sure the ++ * next search doesn't repeat this root ++ */ ++ sk->min_objectid = sh->objectid; ++ sk->min_type = sh->type; ++ sk->min_offset = sh->offset; ++ } ++ if (subvol[0] != '\0') ++ break; ++ sk->nr_items = 4096; ++ /* this iteration is done, step forward one root for the next ++ * ioctl ++ */ ++ if (sk->min_objectid < (u64)-1) { ++ sk->min_objectid++; ++ sk->min_type = BTRFS_ROOT_BACKREF_KEY; ++ sk->min_offset = 0; ++ } else ++ break; ++ } ++ return subvol; ++} ++ + int install_file(const char *path, int devfd, struct stat *rst) + { + if (fs_type == EXT2 || fs_type == VFAT) +@@ -548,19 +811,9 @@ static const char *find_device(const char *mtab_file, dev_t dev) + if (!strcmp(mnt->mnt_type, "btrfs") && + !stat(mnt->mnt_dir, &dst) && + dst.st_dev == dev) { +- char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT); +- +- if (opt) { +- if (!subvol[0]) { +- char *tmp; +- +- strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1); +- tmp = strchr(subvol, 32); +- if (tmp) +- *tmp = '\0'; +- } +- break; /* should break and let upper layer try again */ +- } else ++ if (!subvol[0]) { ++ get_default_subvol(mnt->mnt_dir, subvol); ++ } + done = true; + } + break; +@@ -625,24 +878,10 @@ static const char *get_devname(const char *path) + + #else + +- /* check /etc/mtab first, since btrfs subvol info is only in here */ +- devname = find_device("/etc/mtab", st.st_dev); +- if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */ +- char parent[256]; +- char *tmp; +- +- strcpy(parent, path); +- tmp = strrchr(parent, '/'); +- if (tmp) { +- *tmp = '\0'; +- fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent); +- devname = get_devname(parent); +- } else +- devname = NULL; +- } ++ devname = find_device("/proc/mounts", st.st_dev); + if (!devname) { +- /* Didn't find it in /etc/mtab, try /proc/mounts */ +- devname = find_device("/proc/mounts", st.st_dev); ++ /* Didn't find it in /proc/mounts, try /etc/mtab */ ++ devname = find_device("/etc/mtab", st.st_dev); + } + if (!devname) { + fprintf(stderr, "%s: cannot find device for path %s\n", program, path); +-- +1.7.2.5 +