[PATCH v3 3/3] fs: add support for SquashFS 4.0

Sascha Hauer s.hauer at pengutronix.de
Thu Feb 25 01:38:38 PST 2016


On Fri, Feb 19, 2016 at 03:49:15PM +0100, yegorslists at googlemail.com wrote:
> From: Yegor Yefremov <yegorslists at googlemail.com>
> 
> The driver was imported from Linux 4.4.
> 

> +++ b/fs/squashfs/Kconfig
> @@ -0,0 +1,31 @@
> +menuconfig FS_SQUASHFS
> +	bool
> +	prompt "squashfs support"
> +	help
> +	  Saying Y here includes support for SquashFS 4.0 (a Compressed
> +	  Read-Only File System).  Squashfs is a highly compressed read-only
> +	  filesystem for Linux.  It uses zlib, lzo or xz compression to
> +	  compress both files, inodes and directories.  Inodes in the system
> +	  are very small and all blocks are packed to minimise data overhead.
> +	  Block sizes greater than 4K are supported up to a maximum of 1 Mbytes
> +	  (default block size 128K).  SquashFS 4.0 supports 64 bit filesystems
> +	  and files (larger than 4GB), full uid/gid information, hard links and
> +	  timestamps.
> +
> +	  Squashfs is intended for general read-only filesystem use, for
> +	  archival use (i.e. in cases where a .tar.gz file may be used), and in
> +	  embedded systems where low overhead is needed.  Further information
> +	  and tools are available from http://squashfs.sourceforge.net.
> +
> +config SQUASHFS_XZ
> +	bool "Include support for XZ compressed file systems"
> +	depends on FS_SQUASHFS
> +	select XZ_DECOMPRESS
> +	help
> +	  Saying Y here includes support for reading Squashfs file systems
> +	  compressed with XZ compression.  XZ gives better compression than
> +	  the default zlib compression, at the expense of greater CPU and
> +	  memory overhead.
> +
> +	  XZ is not the standard compression used in Squashfs and so most
> +	  file systems will be readable without selecting this option.

As long as XZ is the only option, does it make sense to make this
visible? I rather suggest an invisible "default y" option.

> +
> +struct squashfs_priv {
> +	struct super_block *sb;
> +};
> +
> +static struct inode *squashfs_findfile(struct super_block *sb,
> +		const char *filename, char *buf)
> +{
> +	char *next;
> +	char fpath[128];
> +	char *name = fpath;
> +	struct inode *inode;
> +	struct inode *t_inode = NULL;
> +
> +	strcpy(fpath, filename);
> +
> +	/* Remove all leading slashes */
> +	while (*name == '/')
> +		name++;
> +
> +	inode = duplicate_inode(sb->s_root->d_inode);
> +
> +	/*
> +	 * Handle root-direcoty ('/')

s/direcoty/directory/

> +	 */
> +	if (!name || *name == '\0')
> +		return inode;
> +
> +	for (;;) {
> +		/* Extract the actual part from the pathname.  */
> +		next = strchr(name, '/');
> +		if (next) {
> +			/* Remove all leading slashes.  */
> +			while (*next == '/')
> +				*(next++) = '\0';
> +		}
> +
> +		t_inode = squashfs_lookup(inode, name, 0);
> +		if (t_inode == NULL)
> +			break;
> +
> +		/*
> +		 * Check if directory with this name exists
> +		 */
> +
> +		/* Found the node!  */
> +		if (!next || *next == '\0') {
> +			if (buf != NULL)
> +				sprintf(buf, "%s", name);
> +
> +			free(squashfs_i(inode));
> +			return t_inode;
> +		}
> +
> +		name = next;
> +
> +		free(squashfs_i(inode));
> +		inode = t_inode;
> +	}
> +
> +	free(squashfs_i(inode));
> +	return NULL;
> +}
> +
> +static int squashfs_probe(struct device_d *dev)
> +{
> +	struct fs_device_d *fsdev;
> +	struct squashfs_priv *priv;
> +	int ret;
> +
> +	fsdev = dev_to_fs_device(dev);
> +
> +	priv = xmalloc(sizeof(struct squashfs_priv));

xzalloc is usually safer here. Even if you know that all fields are
initialized properly later, once we add new fields we usually expect
them to be initialized to zero.

> +	dev->priv = priv;
> +
> +	ret = fsdev_open_cdev(fsdev);
> +	if (ret)
> +		goto err_out;
> +
> +
> +	priv->sb = squashfs_mount(fsdev, 0);

You could embed a struct super_block into struct squashfs_priv. That
would save you one extra allocation.

> +	if (IS_ERR(priv->sb)) {
> +		dev_info(dev, "no valid squashfs found\n");
> +		ret = PTR_ERR(priv->sb);
> +		goto err_out;
> +	}
> +
> +	return 0;
> +
> +err_out:
> +	free(priv);
> +
> +	return ret;
> +}
> +
> +static void squashfs_remove(struct device_d *dev)
> +{
> +	struct squashfs_priv *priv = dev->priv;
> +
> +	squashfs_put_super(priv->sb);
> +	free(priv->sb);
> +	free(priv);
> +}
> +
> +static int squashfs_open(struct device_d *dev, FILE *file, const char *filename)
> +{
> +	struct squashfs_priv *priv = dev->priv;
> +	struct inode *inode;
> +	struct squashfs_page *page;
> +	int i;
> +
> +	inode = squashfs_findfile(priv->sb, filename, NULL);
> +	if (!inode)
> +		return -ENOENT;
> +
> +	page = malloc(sizeof(struct squashfs_page));
> +	page->buf = calloc(32, sizeof(*page->buf));
> +	for (i = 0; i < 32; i++)
> +		page->buf[i] = malloc(PAGE_CACHE_SIZE);

Given the amount of memory you allocate here malloc is a good choice,
but please check the return value.

> +
> +	page->data_block = 0;
> +	page->idx = 0;
> +	page->real_page.inode = inode;
> +	file->size = inode->i_size;
> +	file->priv = page;
> +
> +	return 0;
> +}
> +
> +static int squashfs_close(struct device_d *dev, FILE *f)
> +{
> +	struct squashfs_page *page = f->priv;
> +	int i;
> +
> +	for (i = 0; i < 32; i++)
> +		free(page->buf[i]);
> +
> +	free(page->buf);
> +	free(squashfs_i(page->real_page.inode));
> +	free(page);
> +
> +	return 0;
> +}
> +
> +static int squashfs_read(struct device_d *_dev, FILE *f, void *buf,
> +		size_t insize)
> +{
> +	unsigned int size = insize;
> +	int offset, idx;
> +	int data_block_pos;
> +	struct squashfs_page *page = f->priv;
> +
> +	if (f->pos >= (page->data_block + 1) * 32 * PAGE_CACHE_SIZE) {
> +		page->data_block++;
> +		page->idx = 0;
> +	}

You seem to assume here that files are only read linearly. You have to
do something more clever here to support lseek.

> +
> +	data_block_pos = f->pos - page->data_block * 32 * PAGE_CACHE_SIZE;
> +	idx = data_block_pos / PAGE_CACHE_SIZE;
> +	page->real_page.index = (page->data_block)*32;
> +	offset = data_block_pos - idx * PAGE_CACHE_SIZE;
> +
> +	if (page->idx == 0)
> +		squashfs_readpage(NULL, &page->real_page);
> +
> +	memcpy(buf, page->buf[idx] + offset, size);
> +
> +	return insize;
> +}
> +
> +static loff_t squashfs_lseek(struct device_d *dev, FILE *f, loff_t pos)
> +{
> +	f->pos = pos;
> +
> +	return pos;
> +}
> +

Sascha
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list