libext2fs
authorAnas Nashif <anas.nashif@intel.com>
Sat, 10 Nov 2012 16:33:31 +0000 (08:33 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Sat, 10 Nov 2012 16:33:31 +0000 (08:33 -0800)
libinstaller/linuxioctl.h
packaging/0001-btrfs-Correctly-determine-the-installation-subvolume.patch

index 7ef919a..100fd86 100644 (file)
@@ -19,7 +19,7 @@
 
 #undef SECTOR_SIZE             /* Defined in msdos_fs.h for no good reason */
 #undef SECTOR_BITS
-#include <linux/ext2_fs.h>     /* EXT2_IOC_* */
+#include <ext2fs/ext2_fs.h>    /* EXT2_IOC_* */
 
 #ifndef FAT_IOCTL_GET_ATTRIBUTES
 # define FAT_IOCTL_GET_ATTRIBUTES      _IOR('r', 0x10, __u32)
index e69de29..c5c941f 100644 (file)
@@ -0,0 +1,493 @@
+From c46d7f1567870b9a2bb0a946af741a585e96fe67 Mon Sep 17 00:00:00 2001
+From: Yi Yang <yi.y.yang@intel.com>
+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 <hpa@linux.intel.com>
+---
+ 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 <asm/types.h>
++#include <linux/ioctl.h>
++
+ #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 <inttypes.h>
+ /* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
+-typedef uint64_t u64;
+ #include <alloca.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <unistd.h>
++#include <dirent.h>
+ #ifndef __KLIBC__
+ #include <mntent.h>
+ #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
+