From 4b5397dc24ab12afaac85be3d0863b7f6eb8b0f0 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Fri, 14 May 2010 20:48:47 +0100 Subject: squashfs: add xattr id support This patch adds support for mapping xattr ids (stored in inodes) into the on-disk location of the xattrs themselves. Signed-off-by: Phillip Lougher --- fs/squashfs/Makefile | 2 + fs/squashfs/squashfs.h | 6 +++ fs/squashfs/squashfs_fs.h | 32 +++++++++++++- fs/squashfs/squashfs_fs_sb.h | 3 ++ fs/squashfs/super.c | 22 ++++++++-- fs/squashfs/xattr_id.c | 100 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 fs/squashfs/xattr_id.c diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index df8a19ef870..c0da4a189cc 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_SQUASHFS) += squashfs.o squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o +squashfs-y += xattr_id.o + diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index fe2587af551..133befe2f8b 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -73,6 +73,12 @@ extern struct inode *squashfs_iget(struct super_block *, long long, unsigned int); extern int squashfs_read_inode(struct inode *, long long); +/* xattr_id.c */ +extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, + int *, long long *); +extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, + u64 *, int *); + /* * Inodes, files and decompressor operations */ diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 79024245ea0..c654e863d3c 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -174,6 +174,24 @@ #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ sizeof(u64)) +/* xattr id lookup table defines */ +#define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id)) + +#define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\ + sizeof(u64)) +#define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16)) + +#define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff)) /* cached data constants for filesystem */ #define SQUASHFS_CACHED_BLKS 8 @@ -228,7 +246,7 @@ struct squashfs_super_block { __le64 root_inode; __le64 bytes_used; __le64 id_table_start; - __le64 xattr_table_start; + __le64 xattr_id_table_start; __le64 inode_table_start; __le64 directory_table_start; __le64 fragment_table_start; @@ -377,4 +395,16 @@ struct squashfs_fragment_entry { unsigned int unused; }; +struct squashfs_xattr_id { + __le64 xattr; + __le32 count; + __le32 size; +}; + +struct squashfs_xattr_id_table { + __le64 xattr_table_start; + __le32 xattr_ids; + __le32 unused; +}; + #endif diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 2e77dc547e2..d9037a5215f 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -61,6 +61,7 @@ struct squashfs_sb_info { int next_meta_index; __le64 *id_table; __le64 *fragment_index; + __le64 *xattr_id_table; struct mutex read_data_mutex; struct mutex meta_index_mutex; struct meta_index *meta_index; @@ -68,9 +69,11 @@ struct squashfs_sb_info { __le64 *inode_lookup_table; u64 inode_table; u64 directory_table; + u64 xattr_table; unsigned int block_size; unsigned short block_log; long long bytes_used; unsigned int inodes; + int xattr_ids; }; #endif diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 48b6f4a385a..c4dfc393fa5 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "squashfs_fs.h" #include "squashfs_fs_sb.h" @@ -82,7 +83,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) long long root_inode; unsigned short flags; unsigned int fragments; - u64 lookup_table_start; + u64 lookup_table_start, xattr_id_table_start; int err; TRACE("Entered squashfs_fill_superblock\n"); @@ -143,7 +144,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) * Check if there's xattrs in the filesystem. These are not * supported in this version, so warn that they will be ignored. */ - if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK) + if (le64_to_cpu(sblk->xattr_id_table_start) != SQUASHFS_INVALID_BLK) ERROR("Xattrs in filesystem, these will be ignored\n"); /* Check the filesystem does not extend beyond the end of the @@ -253,7 +254,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) allocate_lookup_table: lookup_table_start = le64_to_cpu(sblk->lookup_table_start); if (lookup_table_start == SQUASHFS_INVALID_BLK) - goto allocate_root; + goto allocate_xattr_table; /* Allocate and read inode lookup table */ msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, @@ -266,6 +267,19 @@ allocate_lookup_table: sb->s_export_op = &squashfs_export_ops; +allocate_xattr_table: + xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); + if (xattr_id_table_start == SQUASHFS_INVALID_BLK) + goto allocate_root; + + /* Allocate and read xattr id lookup table */ + msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, + xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); + if (IS_ERR(msblk->xattr_id_table)) { + err = PTR_ERR(msblk->xattr_id_table); + msblk->xattr_id_table = NULL; + goto failed_mount; + } allocate_root: root = new_inode(sb); if (!root) { @@ -301,6 +315,7 @@ failed_mount: kfree(msblk->inode_lookup_table); kfree(msblk->fragment_index); kfree(msblk->id_table); + kfree(msblk->xattr_id_table); kfree(sb->s_fs_info); sb->s_fs_info = NULL; kfree(sblk); @@ -355,6 +370,7 @@ static void squashfs_put_super(struct super_block *sb) kfree(sbi->fragment_index); kfree(sbi->meta_index); kfree(sbi->inode_lookup_table); + kfree(sbi->xattr_id_table); kfree(sb->s_fs_info); sb->s_fs_info = NULL; } diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c new file mode 100644 index 00000000000..a74101244a9 --- /dev/null +++ b/fs/squashfs/xattr_id.c @@ -0,0 +1,100 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2010 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * xattr_id.c + */ + +/* + * This file implements code to map the 32-bit xattr id stored in the inode + * into the on disk location of the xattr data. + */ + +#include +#include +#include + +#include "squashfs_fs.h" +#include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" +#include "squashfs.h" + +/* + * Map xattr id using the xattr id look up table + */ +int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, + int *count, int *size, long long *xattr) +{ + struct squashfs_sb_info *msblk = sb->s_fs_info; + int block = SQUASHFS_XATTR_BLOCK(index); + int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index); + u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]); + struct squashfs_xattr_id id; + int err; + + err = squashfs_read_metadata(sb, &id, &start_block, &offset, + sizeof(id)); + if (err < 0) + return err; + + *xattr = le64_to_cpu(id.xattr); + *size = le32_to_cpu(id.size); + *count = le32_to_cpu(id.count); + return 0; +} + + +/* + * Read uncompressed xattr id lookup table indexes from disk into memory + */ +__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, + u64 *xattr_table_start, int *xattr_ids) +{ + unsigned int len; + __le64 *xid_table; + struct squashfs_xattr_id_table id_table; + int err; + + err = squashfs_read_table(sb, &id_table, start, sizeof(id_table)); + if (err < 0) { + ERROR("unable to read xattr id table\n"); + return ERR_PTR(err); + } + *xattr_table_start = le64_to_cpu(id_table.xattr_table_start); + *xattr_ids = le32_to_cpu(id_table.xattr_ids); + len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); + + TRACE("In read_xattr_index_table, length %d\n", len); + + /* Allocate xattr id lookup table indexes */ + xid_table = kmalloc(len, GFP_KERNEL); + if (xid_table == NULL) { + ERROR("Failed to allocate xattr id index table\n"); + return ERR_PTR(-ENOMEM); + } + + err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len); + if (err < 0) { + ERROR("unable to read xattr id index table\n"); + kfree(xid_table); + return ERR_PTR(err); + } + + return xid_table; +} -- cgit v1.2.3-18-g5258 From f41d207cbedecd82f797adcce83890aa96f1c9e9 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Mon, 17 May 2010 03:17:04 +0100 Subject: squashfs: add support for xattr reading Add support for listxattr and getxattr. Also add xattr definitions. Signed-off-by: Phillip Lougher --- fs/squashfs/Makefile | 2 +- fs/squashfs/squashfs_fs.h | 19 +++ fs/squashfs/squashfs_fs_i.h | 3 + fs/squashfs/xattr.c | 319 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 fs/squashfs/xattr.c diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index c0da4a189cc..56684d46410 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_SQUASHFS) += squashfs.o squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o -squashfs-y += xattr_id.o +squashfs-y += xattr.o xattr_id.o diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index c654e863d3c..6fe940cf901 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -46,6 +46,7 @@ #define SQUASHFS_NAME_LEN 256 #define SQUASHFS_INVALID_FRAG (0xffffffffU) +#define SQUASHFS_INVALID_XATTR (0xffffffffU) #define SQUASHFS_INVALID_BLK (-1LL) /* Filesystem flags */ @@ -96,6 +97,13 @@ #define SQUASHFS_LFIFO_TYPE 13 #define SQUASHFS_LSOCKET_TYPE 14 +/* Xattr types */ +#define SQUASHFS_XATTR_USER 0 +#define SQUASHFS_XATTR_TRUSTED 1 +#define SQUASHFS_XATTR_SECURITY 2 +#define SQUASHFS_XATTR_VALUE_OOL 256 +#define SQUASHFS_XATTR_PREFIX_MASK 0xff + /* Flag whether block is compressed or uncompressed, bit is set if block is * uncompressed */ #define SQUASHFS_COMPRESSED_BIT (1 << 15) @@ -395,6 +403,17 @@ struct squashfs_fragment_entry { unsigned int unused; }; +struct squashfs_xattr_entry { + __le16 type; + __le16 size; + char data[0]; +}; + +struct squashfs_xattr_val { + __le32 vsize; + char value[0]; +}; + struct squashfs_xattr_id { __le64 xattr; __le32 count; diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h index fbfca30c0c6..d3e3a37f28a 100644 --- a/fs/squashfs/squashfs_fs_i.h +++ b/fs/squashfs/squashfs_fs_i.h @@ -26,6 +26,9 @@ struct squashfs_inode_info { u64 start; int offset; + u64 xattr; + unsigned int xattr_size; + int xattr_count; union { struct { u64 fragment_block; diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c new file mode 100644 index 00000000000..147ecc3f69e --- /dev/null +++ b/fs/squashfs/xattr.c @@ -0,0 +1,319 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2010 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * xattr_id.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "squashfs_fs.h" +#include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" +#include "squashfs.h" + +static inline struct xattr_handler *squashfs_xattr_handler(int); + +ssize_t squashfs_listxattr(struct dentry *d, char *buffer, + size_t buffer_size) +{ + struct inode *inode = d->d_inode; + struct super_block *sb = inode->i_sb; + struct squashfs_sb_info *msblk = sb->s_fs_info; + u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) + + msblk->xattr_table; + int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); + int count = squashfs_i(inode)->xattr_count; + size_t rest = buffer_size; + int err; + + /* check that the file system has xattrs */ + if (msblk->xattr_id_table == NULL) + return -EOPNOTSUPP; + + /* loop reading each xattr name */ + while (count--) { + struct squashfs_xattr_entry entry; + struct squashfs_xattr_val val; + struct xattr_handler *handler; + int name_size, prefix_size = 0; + + err = squashfs_read_metadata(sb, &entry, &start, &offset, + sizeof(entry)); + if (err < 0) + goto failed; + + name_size = le16_to_cpu(entry.size); + handler = squashfs_xattr_handler(le16_to_cpu(entry.type)); + if (handler) + prefix_size = handler->list(d, buffer, rest, NULL, + name_size, handler->flags); + if (prefix_size) { + if (buffer) { + if (prefix_size + name_size + 1 > rest) { + err = -ERANGE; + goto failed; + } + buffer += prefix_size; + } + err = squashfs_read_metadata(sb, buffer, &start, + &offset, name_size); + if (err < 0) + goto failed; + if (buffer) { + buffer[name_size] = '\0'; + buffer += name_size + 1; + } + rest -= prefix_size + name_size + 1; + } else { + /* no handler or insuffficient privileges, so skip */ + err = squashfs_read_metadata(sb, NULL, &start, + &offset, name_size); + if (err < 0) + goto failed; + } + + + /* skip remaining xattr entry */ + err = squashfs_read_metadata(sb, &val, &start, &offset, + sizeof(val)); + if (err < 0) + goto failed; + + err = squashfs_read_metadata(sb, NULL, &start, &offset, + le32_to_cpu(val.vsize)); + if (err < 0) + goto failed; + } + err = buffer_size - rest; + +failed: + return err; +} + + +static int squashfs_xattr_get(struct inode *inode, int name_index, + const char *name, void *buffer, size_t buffer_size) +{ + struct super_block *sb = inode->i_sb; + struct squashfs_sb_info *msblk = sb->s_fs_info; + u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) + + msblk->xattr_table; + int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); + int count = squashfs_i(inode)->xattr_count; + int name_len = strlen(name); + int err, vsize; + char *target = kmalloc(name_len, GFP_KERNEL); + + if (target == NULL) + return -ENOMEM; + + /* loop reading each xattr name */ + for (; count; count--) { + struct squashfs_xattr_entry entry; + struct squashfs_xattr_val val; + int type, prefix, name_size; + + err = squashfs_read_metadata(sb, &entry, &start, &offset, + sizeof(entry)); + if (err < 0) + goto failed; + + name_size = le16_to_cpu(entry.size); + type = le16_to_cpu(entry.type); + prefix = type & SQUASHFS_XATTR_PREFIX_MASK; + + err = squashfs_read_metadata(sb, target, &start, &offset, + name_size); + if (err < 0) + goto failed; + + if (prefix == name_index && name_size == name_len && + strncmp(target, name, name_size) == 0) { + /* found xattr */ + if (type & SQUASHFS_XATTR_VALUE_OOL) { + __le64 xattr; + /* val is a reference to the real location */ + err = squashfs_read_metadata(sb, &val, &start, + &offset, sizeof(val)); + if (err < 0) + goto failed; + err = squashfs_read_metadata(sb, &xattr, &start, + &offset, sizeof(xattr)); + if (err < 0) + goto failed; + xattr = le64_to_cpu(xattr); + start = SQUASHFS_XATTR_BLK(xattr) + + msblk->xattr_table; + offset = SQUASHFS_XATTR_OFFSET(xattr); + } + /* read xattr value */ + err = squashfs_read_metadata(sb, &val, &start, &offset, + sizeof(val)); + if (err < 0) + goto failed; + + vsize = le32_to_cpu(val.vsize); + if (buffer) { + if (vsize > buffer_size) { + err = -ERANGE; + goto failed; + } + err = squashfs_read_metadata(sb, buffer, &start, + &offset, vsize); + if (err < 0) + goto failed; + } + break; + } + + /* no match, skip remaining xattr entry */ + err = squashfs_read_metadata(sb, &val, &start, &offset, + sizeof(val)); + if (err < 0) + goto failed; + err = squashfs_read_metadata(sb, NULL, &start, &offset, + le32_to_cpu(val.vsize)); + if (err < 0) + goto failed; + } + err = count ? vsize : -ENODATA; + +failed: + kfree(target); + return err; +} + + +/* + * User namespace support + */ +static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size, + const char *name, size_t name_len, int type) +{ + if (list && XATTR_USER_PREFIX_LEN <= list_size) + memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); + return XATTR_USER_PREFIX_LEN; +} + +static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, + size_t size, int type) +{ + if (name[0] == '\0') + return -EINVAL; + + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name, + buffer, size); +} + +struct xattr_handler squashfs_xattr_user_handler = { + .prefix = XATTR_USER_PREFIX, + .list = squashfs_user_list, + .get = squashfs_user_get +}; + +/* + * Trusted namespace support + */ +static size_t squashfs_trusted_list(struct dentry *d, char *list, + size_t list_size, const char *name, size_t name_len, int type) +{ + if (!capable(CAP_SYS_ADMIN)) + return 0; + + if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size) + memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); + return XATTR_TRUSTED_PREFIX_LEN; +} + +static int squashfs_trusted_get(struct dentry *d, const char *name, + void *buffer, size_t size, int type) +{ + if (name[0] == '\0') + return -EINVAL; + + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name, + buffer, size); +} + +struct xattr_handler squashfs_xattr_trusted_handler = { + .prefix = XATTR_TRUSTED_PREFIX, + .list = squashfs_trusted_list, + .get = squashfs_trusted_get +}; + +/* + * Security namespace support + */ +static size_t squashfs_security_list(struct dentry *d, char *list, + size_t list_size, const char *name, size_t name_len, int type) +{ + if (list && XATTR_SECURITY_PREFIX_LEN <= list_size) + memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); + return XATTR_SECURITY_PREFIX_LEN; +} + +static int squashfs_security_get(struct dentry *d, const char *name, + void *buffer, size_t size, int type) +{ + if (name[0] == '\0') + return -EINVAL; + + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name, + buffer, size); +} + +struct xattr_handler squashfs_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = squashfs_security_list, + .get = squashfs_security_get +}; + +static inline struct xattr_handler *squashfs_xattr_handler(int type) +{ + if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) + /* ignore unrecognised type */ + return NULL; + + switch (type & SQUASHFS_XATTR_PREFIX_MASK) { + case SQUASHFS_XATTR_USER: + return &squashfs_xattr_user_handler; + case SQUASHFS_XATTR_TRUSTED: + return &squashfs_xattr_trusted_handler; + case SQUASHFS_XATTR_SECURITY: + return &squashfs_xattr_security_handler; + default: + /* ignore unrecognised type */ + return NULL; + } +} + +struct xattr_handler *squashfs_xattr_handlers[] = { + &squashfs_xattr_user_handler, + &squashfs_xattr_trusted_handler, + &squashfs_xattr_security_handler, + NULL +}; + -- cgit v1.2.3-18-g5258 From 67f66cc6c728de183d9d43c243cb163c1ebd8e04 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Mon, 17 May 2010 04:06:56 +0100 Subject: squashfs: add new extended inode types Add new extended inode types that store the xattr_id field. Also add the necessary code changes to make xattrs visibile. Signed-off-by: Phillip Lougher --- fs/squashfs/inode.c | 91 +++++++++++++++++++++++++++++++++++++++++++---- fs/squashfs/namei.c | 5 ++- fs/squashfs/squashfs.h | 12 ++++++- fs/squashfs/squashfs_fs.h | 25 +++++++++++++ fs/squashfs/super.c | 8 +---- fs/squashfs/symlink.c | 10 ++++++ 6 files changed, 135 insertions(+), 16 deletions(-) diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 49daaf669e4..250701180a3 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -40,6 +40,7 @@ #include #include +#include #include "squashfs_fs.h" #include "squashfs_fs_sb.h" @@ -111,6 +112,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) int err, type, offset = SQUASHFS_INODE_OFFSET(ino); union squashfs_inode squashfs_ino; struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; + int xattr_id = SQUASHFS_INVALID_XATTR; TRACE("Entered squashfs_read_inode\n"); @@ -199,8 +201,10 @@ int squashfs_read_inode(struct inode *inode, long long ino) frag_offset = 0; } + xattr_id = le32_to_cpu(sqsh_ino->xattr); inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); inode->i_size = le64_to_cpu(sqsh_ino->file_size); + inode->i_op = &squashfs_inode_ops; inode->i_fop = &generic_ro_fops; inode->i_mode |= S_IFREG; inode->i_blocks = ((inode->i_size - @@ -251,6 +255,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) if (err < 0) goto failed_read; + xattr_id = le32_to_cpu(sqsh_ino->xattr); inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); inode->i_size = le32_to_cpu(sqsh_ino->file_size); inode->i_op = &squashfs_dir_inode_ops; @@ -280,21 +285,33 @@ int squashfs_read_inode(struct inode *inode, long long ino) inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &squashfs_symlink_inode_ops; inode->i_data.a_ops = &squashfs_symlink_aops; inode->i_mode |= S_IFLNK; squashfs_i(inode)->start = block; squashfs_i(inode)->offset = offset; + if (type == SQUASHFS_LSYMLINK_TYPE) { + __le32 xattr; + + err = squashfs_read_metadata(sb, NULL, &block, + &offset, inode->i_size); + if (err < 0) + goto failed_read; + err = squashfs_read_metadata(sb, &xattr, &block, + &offset, sizeof(xattr)); + if (err < 0) + goto failed_read; + xattr_id = le32_to_cpu(xattr); + } + TRACE("Symbolic link inode %x:%x, start_block %llx, offset " "%x\n", SQUASHFS_INODE_BLK(ino), offset, block, offset); break; } case SQUASHFS_BLKDEV_TYPE: - case SQUASHFS_CHRDEV_TYPE: - case SQUASHFS_LBLKDEV_TYPE: - case SQUASHFS_LCHRDEV_TYPE: { + case SQUASHFS_CHRDEV_TYPE: { struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; unsigned int rdev; @@ -315,10 +332,32 @@ int squashfs_read_inode(struct inode *inode, long long ino) SQUASHFS_INODE_BLK(ino), offset, rdev); break; } + case SQUASHFS_LBLKDEV_TYPE: + case SQUASHFS_LCHRDEV_TYPE: { + struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev; + unsigned int rdev; + + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, + sizeof(*sqsh_ino)); + if (err < 0) + goto failed_read; + + if (type == SQUASHFS_LCHRDEV_TYPE) + inode->i_mode |= S_IFCHR; + else + inode->i_mode |= S_IFBLK; + xattr_id = le32_to_cpu(sqsh_ino->xattr); + inode->i_op = &squashfs_inode_ops; + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); + rdev = le32_to_cpu(sqsh_ino->rdev); + init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); + + TRACE("Device inode %x:%x, rdev %x\n", + SQUASHFS_INODE_BLK(ino), offset, rdev); + break; + } case SQUASHFS_FIFO_TYPE: - case SQUASHFS_SOCKET_TYPE: - case SQUASHFS_LFIFO_TYPE: - case SQUASHFS_LSOCKET_TYPE: { + case SQUASHFS_SOCKET_TYPE: { struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, @@ -334,14 +373,52 @@ int squashfs_read_inode(struct inode *inode, long long ino) init_special_inode(inode, inode->i_mode, 0); break; } + case SQUASHFS_LFIFO_TYPE: + case SQUASHFS_LSOCKET_TYPE: { + struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc; + + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, + sizeof(*sqsh_ino)); + if (err < 0) + goto failed_read; + + if (type == SQUASHFS_LFIFO_TYPE) + inode->i_mode |= S_IFIFO; + else + inode->i_mode |= S_IFSOCK; + xattr_id = le32_to_cpu(sqsh_ino->xattr); + inode->i_op = &squashfs_inode_ops; + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); + init_special_inode(inode, inode->i_mode, 0); + break; + } default: ERROR("Unknown inode type %d in squashfs_iget!\n", type); return -EINVAL; } + if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) { + err = squashfs_xattr_lookup(sb, xattr_id, + &squashfs_i(inode)->xattr_count, + &squashfs_i(inode)->xattr_size, + &squashfs_i(inode)->xattr); + if (err < 0) + goto failed_read; + inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9) + + 1; + } else + squashfs_i(inode)->xattr_count = 0; + return 0; failed_read: ERROR("Unable to read inode 0x%llx\n", ino); return err; } + + +const struct inode_operations squashfs_inode_ops = { + .getxattr = generic_getxattr, + .listxattr = squashfs_listxattr +}; + diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c index 5266bd8ad93..32f5b54d1ce 100644 --- a/fs/squashfs/namei.c +++ b/fs/squashfs/namei.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "squashfs_fs.h" #include "squashfs_fs_sb.h" @@ -237,5 +238,7 @@ failed: const struct inode_operations squashfs_dir_inode_ops = { - .lookup = squashfs_lookup + .lookup = squashfs_lookup, + .getxattr = generic_getxattr, + .listxattr = squashfs_listxattr }; diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 133befe2f8b..7d238107058 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -73,6 +73,9 @@ extern struct inode *squashfs_iget(struct super_block *, long long, unsigned int); extern int squashfs_read_inode(struct inode *, long long); +/* xattr.c */ +extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t); + /* xattr_id.c */ extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, int *, long long *); @@ -80,7 +83,7 @@ extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, u64 *, int *); /* - * Inodes, files and decompressor operations + * Inodes, files, decompressor and xattr operations */ /* dir.c */ @@ -92,11 +95,18 @@ extern const struct export_operations squashfs_export_ops; /* file.c */ extern const struct address_space_operations squashfs_aops; +/* inode.c */ +extern const struct inode_operations squashfs_inode_ops; + /* namei.c */ extern const struct inode_operations squashfs_dir_inode_ops; /* symlink.c */ extern const struct address_space_operations squashfs_symlink_aops; +extern const struct inode_operations squashfs_symlink_inode_ops; + +/* xattr.c */ +extern struct xattr_handler *squashfs_xattr_handlers[]; /* zlib_wrapper.c */ extern const struct squashfs_decompressor squashfs_zlib_comp_ops; diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 6fe940cf901..8eabb808b78 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -287,6 +287,17 @@ struct squashfs_ipc_inode { __le32 nlink; }; +struct squashfs_lipc_inode { + __le16 inode_type; + __le16 mode; + __le16 uid; + __le16 guid; + __le32 mtime; + __le32 inode_number; + __le32 nlink; + __le32 xattr; +}; + struct squashfs_dev_inode { __le16 inode_type; __le16 mode; @@ -298,6 +309,18 @@ struct squashfs_dev_inode { __le32 rdev; }; +struct squashfs_ldev_inode { + __le16 inode_type; + __le16 mode; + __le16 uid; + __le16 guid; + __le32 mtime; + __le32 inode_number; + __le32 nlink; + __le32 rdev; + __le32 xattr; +}; + struct squashfs_symlink_inode { __le16 inode_type; __le16 mode; @@ -375,12 +398,14 @@ struct squashfs_ldir_inode { union squashfs_inode { struct squashfs_base_inode base; struct squashfs_dev_inode dev; + struct squashfs_ldev_inode ldev; struct squashfs_symlink_inode symlink; struct squashfs_reg_inode reg; struct squashfs_lreg_inode lreg; struct squashfs_dir_inode dir; struct squashfs_ldir_inode ldir; struct squashfs_ipc_inode ipc; + struct squashfs_lipc_inode lipc; }; struct squashfs_dir_entry { diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index c4dfc393fa5..b6425ac1c2a 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -140,13 +140,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) if (msblk->decompressor == NULL) goto failed_mount; - /* - * Check if there's xattrs in the filesystem. These are not - * supported in this version, so warn that they will be ignored. - */ - if (le64_to_cpu(sblk->xattr_id_table_start) != SQUASHFS_INVALID_BLK) - ERROR("Xattrs in filesystem, these will be ignored\n"); - /* Check the filesystem does not extend beyond the end of the block device */ msblk->bytes_used = le64_to_cpu(sblk->bytes_used); @@ -268,6 +261,7 @@ allocate_lookup_table: sb->s_export_op = &squashfs_export_ops; allocate_xattr_table: + sb->s_xattr = squashfs_xattr_handlers; xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); if (xattr_id_table_start == SQUASHFS_INVALID_BLK) goto allocate_root; diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index 32b911f4ee3..a7ee68a8621 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "squashfs_fs.h" #include "squashfs_fs_sb.h" @@ -114,3 +115,12 @@ error_out: const struct address_space_operations squashfs_symlink_aops = { .readpage = squashfs_symlink_readpage }; + +const struct inode_operations squashfs_symlink_inode_ops = { + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, + .getxattr = generic_getxattr, + .listxattr = squashfs_listxattr +}; + -- cgit v1.2.3-18-g5258 From 01e5b4e4e897fce8c7e6236bc933c9721c7ee237 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Mon, 17 May 2010 19:39:02 +0100 Subject: squashfs: add xattr support configure option Signed-off-by: Phillip Lougher --- fs/squashfs/Kconfig | 11 +++++++++++ fs/squashfs/Makefile | 2 +- fs/squashfs/inode.c | 1 + fs/squashfs/namei.c | 1 + fs/squashfs/squashfs.h | 6 ------ fs/squashfs/super.c | 4 +++- fs/squashfs/symlink.c | 1 + fs/squashfs/xattr.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 fs/squashfs/xattr.h diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index 25a00d19d68..cc6ce8a84c2 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig @@ -26,6 +26,17 @@ config SQUASHFS If unsure, say N. +config SQUASHFS_XATTRS + bool "Squashfs XATTR support" + depends on SQUASHFS + default n + help + Saying Y here includes support for extended attributes (xattrs). + Xattrs are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page). + + If unsure, say N. + config SQUASHFS_EMBEDDED bool "Additional option for memory-constrained systems" diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 56684d46410..2cee3e9fa45 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_SQUASHFS) += squashfs.o squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o -squashfs-y += xattr.o xattr_id.o +squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 250701180a3..62e63ad2507 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -46,6 +46,7 @@ #include "squashfs_fs_sb.h" #include "squashfs_fs_i.h" #include "squashfs.h" +#include "xattr.h" /* * Initialise VFS inode with the base inode information common to all diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c index 32f5b54d1ce..7a9464d08cf 100644 --- a/fs/squashfs/namei.c +++ b/fs/squashfs/namei.c @@ -63,6 +63,7 @@ #include "squashfs_fs_sb.h" #include "squashfs_fs_i.h" #include "squashfs.h" +#include "xattr.h" /* * Lookup name in the directory index, returning the location of the metadata diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 7d238107058..305ce15d2d2 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -76,12 +76,6 @@ extern int squashfs_read_inode(struct inode *, long long); /* xattr.c */ extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t); -/* xattr_id.c */ -extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, - int *, long long *); -extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, - u64 *, int *); - /* * Inodes, files, decompressor and xattr operations */ diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index b6425ac1c2a..88b4f860665 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -43,6 +43,7 @@ #include "squashfs_fs_i.h" #include "squashfs.h" #include "decompressor.h" +#include "xattr.h" static struct file_system_type squashfs_fs_type; static const struct super_operations squashfs_super_ops; @@ -272,7 +273,8 @@ allocate_xattr_table: if (IS_ERR(msblk->xattr_id_table)) { err = PTR_ERR(msblk->xattr_id_table); msblk->xattr_id_table = NULL; - goto failed_mount; + if (err != -ENOTSUPP) + goto failed_mount; } allocate_root: root = new_inode(sb); diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index a7ee68a8621..ec86434921e 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c @@ -41,6 +41,7 @@ #include "squashfs_fs_sb.h" #include "squashfs_fs_i.h" #include "squashfs.h" +#include "xattr.h" static int squashfs_symlink_readpage(struct file *file, struct page *page) { diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h new file mode 100644 index 00000000000..4a96366bfcc --- /dev/null +++ b/fs/squashfs/xattr.h @@ -0,0 +1,45 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2010 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * xattr.h + */ + +#ifdef CONFIG_SQUASHFS_XATTRS +extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, + u64 *, int *); +extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, + int *, long long *); +#else +static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, + u64 start, u64 *xattr_table_start, int *xattr_ids) +{ + ERROR("Xattrs in filesystem, these will be ignored\n"); + return ERR_PTR(-ENOTSUPP); +} + +static inline int squashfs_xattr_lookup(struct super_block *sb, + unsigned int index, int *count, int *size, long long *xattr) +{ + return 0; +} +#define squashfs_listxattr NULL +#define generic_getxattr NULL +#define squashfs_xattr_handlers NULL +#endif -- cgit v1.2.3-18-g5258 From aa5b1894cbc700d7462947c017ca9b7bcda1e8ed Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 13 May 2010 16:32:21 -0700 Subject: squashfs: xattr_lookup sparse fix Sparse detected that unsigned pointer was being passed as int pointer. Signed-off-by: Stephen Hemminger [fixed up to deal with code refactoring] Signed-off-by: Phillip Lougher --- fs/squashfs/xattr.h | 5 +++-- fs/squashfs/xattr_id.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index 4a96366bfcc..9da071ae181 100644 --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h @@ -25,7 +25,7 @@ extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, u64 *, int *); extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, - int *, long long *); + int *, unsigned long long *); #else static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, u64 *xattr_table_start, int *xattr_ids) @@ -35,7 +35,8 @@ static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, } static inline int squashfs_xattr_lookup(struct super_block *sb, - unsigned int index, int *count, int *size, long long *xattr) + unsigned int index, int *count, int *size, + unsigned long long *xattr) { return 0; } diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c index a74101244a9..cfb41106098 100644 --- a/fs/squashfs/xattr_id.c +++ b/fs/squashfs/xattr_id.c @@ -39,7 +39,7 @@ * Map xattr id using the xattr id look up table */ int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, - int *count, int *size, long long *xattr) + int *count, unsigned int *size, unsigned long long *xattr) { struct squashfs_sb_info *msblk = sb->s_fs_info; int block = SQUASHFS_XATTR_BLOCK(index); -- cgit v1.2.3-18-g5258 From 0f87ee08564b95389e609699990725efd282021c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 13 May 2010 16:32:22 -0700 Subject: squashfs: xattr fix sparse warnings Sparse does not like inline function declared without body, because it is not part of the standard kernel practice. The xattr_handler tables can be declared static. Signed-off-by: Stephen Hemminger Signed-off-by: Phillip Lougher --- fs/squashfs/xattr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 147ecc3f69e..de03889050b 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -34,7 +34,7 @@ #include "squashfs_fs_i.h" #include "squashfs.h" -static inline struct xattr_handler *squashfs_xattr_handler(int); +static struct xattr_handler *squashfs_xattr_handler(int); ssize_t squashfs_listxattr(struct dentry *d, char *buffer, size_t buffer_size) @@ -228,7 +228,7 @@ static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, buffer, size); } -struct xattr_handler squashfs_xattr_user_handler = { +static struct xattr_handler squashfs_xattr_user_handler = { .prefix = XATTR_USER_PREFIX, .list = squashfs_user_list, .get = squashfs_user_get @@ -258,7 +258,7 @@ static int squashfs_trusted_get(struct dentry *d, const char *name, buffer, size); } -struct xattr_handler squashfs_xattr_trusted_handler = { +static struct xattr_handler squashfs_xattr_trusted_handler = { .prefix = XATTR_TRUSTED_PREFIX, .list = squashfs_trusted_list, .get = squashfs_trusted_get @@ -285,7 +285,7 @@ static int squashfs_security_get(struct dentry *d, const char *name, buffer, size); } -struct xattr_handler squashfs_xattr_security_handler = { +static struct xattr_handler squashfs_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, .list = squashfs_security_list, .get = squashfs_security_get -- cgit v1.2.3-18-g5258 From f6db25a87643fa6108e211da0397423593ca36fe Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Sun, 23 May 2010 03:29:26 +0100 Subject: squashfs: constify xattr handlers Signed-off-by: Phillip Lougher --- fs/squashfs/squashfs.h | 2 +- fs/squashfs/xattr.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 305ce15d2d2..733a17c4294 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -100,7 +100,7 @@ extern const struct address_space_operations squashfs_symlink_aops; extern const struct inode_operations squashfs_symlink_inode_ops; /* xattr.c */ -extern struct xattr_handler *squashfs_xattr_handlers[]; +extern const struct xattr_handler *squashfs_xattr_handlers[]; /* zlib_wrapper.c */ extern const struct squashfs_decompressor squashfs_zlib_comp_ops; diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index de03889050b..14a2feef09b 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -34,7 +34,7 @@ #include "squashfs_fs_i.h" #include "squashfs.h" -static struct xattr_handler *squashfs_xattr_handler(int); +static const struct xattr_handler *squashfs_xattr_handler(int); ssize_t squashfs_listxattr(struct dentry *d, char *buffer, size_t buffer_size) @@ -57,7 +57,7 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer, while (count--) { struct squashfs_xattr_entry entry; struct squashfs_xattr_val val; - struct xattr_handler *handler; + const struct xattr_handler *handler; int name_size, prefix_size = 0; err = squashfs_read_metadata(sb, &entry, &start, &offset, @@ -228,7 +228,7 @@ static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, buffer, size); } -static struct xattr_handler squashfs_xattr_user_handler = { +static const struct xattr_handler squashfs_xattr_user_handler = { .prefix = XATTR_USER_PREFIX, .list = squashfs_user_list, .get = squashfs_user_get @@ -258,7 +258,7 @@ static int squashfs_trusted_get(struct dentry *d, const char *name, buffer, size); } -static struct xattr_handler squashfs_xattr_trusted_handler = { +static const struct xattr_handler squashfs_xattr_trusted_handler = { .prefix = XATTR_TRUSTED_PREFIX, .list = squashfs_trusted_list, .get = squashfs_trusted_get @@ -285,13 +285,13 @@ static int squashfs_security_get(struct dentry *d, const char *name, buffer, size); } -static struct xattr_handler squashfs_xattr_security_handler = { +static const struct xattr_handler squashfs_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, .list = squashfs_security_list, .get = squashfs_security_get }; -static inline struct xattr_handler *squashfs_xattr_handler(int type) +static inline const struct xattr_handler *squashfs_xattr_handler(int type) { if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) /* ignore unrecognised type */ @@ -310,7 +310,7 @@ static inline struct xattr_handler *squashfs_xattr_handler(int type) } } -struct xattr_handler *squashfs_xattr_handlers[] = { +const struct xattr_handler *squashfs_xattr_handlers[] = { &squashfs_xattr_user_handler, &squashfs_xattr_trusted_handler, &squashfs_xattr_security_handler, -- cgit v1.2.3-18-g5258 From 5c80f5aa409b211ab193c56fb6b77d73b61966e5 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Sun, 23 May 2010 08:27:42 +0100 Subject: squashfs: fix name reading in squashfs_xattr_get Only read potentially matching names into the target buffer, all obviously non matching names don't need to be read into the target buffer. Signed-off-by: Phillip Lougher --- fs/squashfs/xattr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 14a2feef09b..c7655e8b31c 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -145,8 +145,12 @@ static int squashfs_xattr_get(struct inode *inode, int name_index, type = le16_to_cpu(entry.type); prefix = type & SQUASHFS_XATTR_PREFIX_MASK; - err = squashfs_read_metadata(sb, target, &start, &offset, - name_size); + if (prefix == name_index && name_size == name_len) + err = squashfs_read_metadata(sb, target, &start, + &offset, name_size); + else + err = squashfs_read_metadata(sb, NULL, &start, + &offset, name_size); if (err < 0) goto failed; -- cgit v1.2.3-18-g5258 From 899f4530334da9292556e1f8f5791468e0136ff1 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 25 May 2010 02:47:00 +0100 Subject: squashfs: update documentation to include description of xattr layout Signed-off-by: Phillip Lougher --- Documentation/filesystems/squashfs.txt | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index b324c033035..203f7202cc9 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt @@ -38,7 +38,8 @@ Hard link support: yes no Real inode numbers: yes no 32-bit uids/gids: yes no File creation time: yes no -Xattr and ACL support: no no +Xattr support: yes no +ACL support: no no Squashfs compresses data, inodes and directories. In addition, inode and directory data are highly compacted, and packed on byte boundaries. Each @@ -58,7 +59,7 @@ obtained from this site also. 3. SQUASHFS FILESYSTEM DESIGN ----------------------------- -A squashfs filesystem consists of seven parts, packed together on a byte +A squashfs filesystem consists of a maximum of eight parts, packed together on a byte alignment: --------------- @@ -80,6 +81,9 @@ alignment: |---------------| | uid/gid | | lookup table | + |---------------| + | xattr | + | table | --------------- Compressed data blocks are written to the filesystem as files are read from @@ -192,6 +196,26 @@ This table is stored compressed into metadata blocks. A second index table is used to locate these. This second index table for speed of access (and because it is small) is read at mount time and cached in memory. +3.7 Xattr table +--------------- + +The xattr table contains extended attributes for each inode. The xattrs +for each inode are stored in a list, each list entry containing a type, +name and value field. The type field encodes the xattr prefix +("user.", "trusted." etc) and it also encodes how the name/value fields +should be interpreted. Currently the type indicates whether the value +is stored inline (in which case the value field contains the xattr value), +or if it is stored out of line (in which case the value field stores a +reference to where the actual value is stored). This allows large values +to be stored out of line improving scanning and lookup performance and it +also allows values to be de-duplicated, the value being stored once, and +all other occurences holding an out of line reference to that value. + +The xattr lists are packed into compressed 8K metadata blocks. +To reduce overhead in inodes, rather than storing the on-disk +location of the xattr list inside each inode, a 32-bit xattr id +is stored. This xattr id is mapped into the location of the xattr +list using a second xattr id lookup table. 4. TODOS AND OUTSTANDING ISSUES ------------------------------- @@ -199,9 +223,7 @@ it is small) is read at mount time and cached in memory. 4.1 Todo list ------------- -Implement Xattr and ACL support. The Squashfs 4.0 filesystem layout has hooks -for these but the code has not been written. Once the code has been written -the existing layout should not require modification. +Implement ACL support. 4.2 Squashfs internal cache --------------------------- -- cgit v1.2.3-18-g5258