Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus
Browse files Browse the repository at this point in the history
* git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus:
  squashfs: update documentation to include description of xattr layout
  squashfs: fix name reading in squashfs_xattr_get
  squashfs: constify xattr handlers
  squashfs: xattr fix sparse warnings
  squashfs: xattr_lookup sparse fix
  squashfs: add xattr support configure option
  squashfs: add new extended inode types
  squashfs: add support for xattr reading
  squashfs: add xattr id support
  • Loading branch information
Linus Torvalds committed May 26, 2010
2 parents f45471c + 899f453 commit 63a6440
Show file tree
Hide file tree
Showing 14 changed files with 723 additions and 24 deletions.
32 changes: 27 additions & 5 deletions Documentation/filesystems/squashfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:

---------------
Expand All @@ -80,6 +81,9 @@ alignment:
|---------------|
| uid/gid |
| lookup table |
|---------------|
| xattr |
| table |
---------------

Compressed data blocks are written to the filesystem as files are read from
Expand Down Expand Up @@ -192,16 +196,34 @@ 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
-------------------------------

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
---------------------------
Expand Down
11 changes: 11 additions & 0 deletions fs/squashfs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions fs/squashfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o

92 changes: 85 additions & 7 deletions fs/squashfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@

#include <linux/fs.h>
#include <linux/vfs.h>
#include <linux/xattr.h>

#include "squashfs_fs.h"
#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
Expand Down Expand Up @@ -111,6 +113,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");

Expand Down Expand Up @@ -199,8 +202,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 -
Expand Down Expand Up @@ -251,6 +256,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;
Expand Down Expand Up @@ -280,21 +286,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;

Expand All @@ -315,10 +333,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,
Expand All @@ -334,14 +374,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
};

6 changes: 5 additions & 1 deletion fs/squashfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/dcache.h>
#include <linux/xattr.h>

#include "squashfs_fs.h"
#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
Expand Down Expand Up @@ -237,5 +239,7 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,


const struct inode_operations squashfs_dir_inode_ops = {
.lookup = squashfs_lookup
.lookup = squashfs_lookup,
.getxattr = generic_getxattr,
.listxattr = squashfs_listxattr
};
12 changes: 11 additions & 1 deletion fs/squashfs/squashfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ 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);

/*
* Inodes, files and decompressor operations
* Inodes, files, decompressor and xattr operations
*/

/* dir.c */
Expand All @@ -86,11 +89,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 const struct xattr_handler *squashfs_xattr_handlers[];

/* zlib_wrapper.c */
extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
Loading

0 comments on commit 63a6440

Please sign in to comment.