Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus

* git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus:
Squashfs: Use vmalloc rather than kmalloc for zlib workspace
Squashfs: handle corruption of directory structure
Squashfs: wrap squashfs_mount() definition
Squashfs: xz_wrapper doesn't need to include squashfs_fs_i.h anymore
Squashfs: Update documentation to include compression options
Squashfs: Update Kconfig help text to include xz compression
Squashfs: add compression options support to xz decompressor
Squashfs: extend decompressor framework to handle compression options

+146 -45
+19 -9
Documentation/filesystems/squashfs.txt
··· 59 59 3. SQUASHFS FILESYSTEM DESIGN 60 60 ----------------------------- 61 61 62 - A squashfs filesystem consists of a maximum of eight parts, packed together on a byte 63 - alignment: 62 + A squashfs filesystem consists of a maximum of nine parts, packed together on a 63 + byte alignment: 64 64 65 65 --------------- 66 66 | superblock | 67 + |---------------| 68 + | compression | 69 + | options | 67 70 |---------------| 68 71 | datablocks | 69 72 | & fragments | ··· 94 91 written the completed inode, directory, fragment, export and uid/gid lookup 95 92 tables are written. 96 93 97 - 3.1 Inodes 94 + 3.1 Compression options 95 + ----------------------- 96 + 97 + Compressors can optionally support compression specific options (e.g. 98 + dictionary size). If non-default compression options have been used, then 99 + these are stored here. 100 + 101 + 3.2 Inodes 98 102 ---------- 99 103 100 104 Metadata (inodes and directories) are compressed in 8Kbyte blocks. Each ··· 124 114 regular files and directories, and extended types where extra 125 115 information has to be stored. 126 116 127 - 3.2 Directories 117 + 3.3 Directories 128 118 --------------- 129 119 130 120 Like inodes, directories are packed into compressed metadata blocks, stored ··· 154 144 This scheme has the advantage that it doesn't require extra memory overhead 155 145 and doesn't require much extra storage on disk. 156 146 157 - 3.3 File data 147 + 3.4 File data 158 148 ------------- 159 149 160 150 Regular files consist of a sequence of contiguous compressed blocks, and/or a ··· 173 163 The index cache is designed to be memory efficient, and by default uses 174 164 16 KiB. 175 165 176 - 3.4 Fragment lookup table 166 + 3.5 Fragment lookup table 177 167 ------------------------- 178 168 179 169 Regular files can contain a fragment index which is mapped to a fragment ··· 183 173 speed of access (and because it is small) is read at mount time and cached 184 174 in memory. 185 175 186 - 3.5 Uid/gid lookup table 176 + 3.6 Uid/gid lookup table 187 177 ------------------------ 188 178 189 179 For space efficiency regular files store uid and gid indexes, which are ··· 192 182 locate these. This second index table for speed of access (and because it 193 183 is small) is read at mount time and cached in memory. 194 184 195 - 3.6 Export table 185 + 3.7 Export table 196 186 ---------------- 197 187 198 188 To enable Squashfs filesystems to be exportable (via NFS etc.) filesystems ··· 206 196 used to locate these. This second index table for speed of access (and because 207 197 it is small) is read at mount time and cached in memory. 208 198 209 - 3.7 Xattr table 199 + 3.8 Xattr table 210 200 --------------- 211 201 212 202 The xattr table contains extended attributes for each inode. The xattrs
+6 -6
fs/squashfs/Kconfig
··· 5 5 help 6 6 Saying Y here includes support for SquashFS 4.0 (a Compressed 7 7 Read-Only File System). Squashfs is a highly compressed read-only 8 - filesystem for Linux. It uses zlib/lzo compression to compress both 9 - files, inodes and directories. Inodes in the system are very small 10 - and all blocks are packed to minimise data overhead. Block sizes 11 - greater than 4K are supported up to a maximum of 1 Mbytes (default 12 - block size 128K). SquashFS 4.0 supports 64 bit filesystems and files 13 - (larger than 4GB), full uid/gid information, hard links and 8 + filesystem for Linux. It uses zlib, lzo or xz compression to 9 + compress both files, inodes and directories. Inodes in the system 10 + are very small and all blocks are packed to minimise data overhead. 11 + Block sizes greater than 4K are supported up to a maximum of 1 Mbytes 12 + (default block size 128K). SquashFS 4.0 supports 64 bit filesystems 13 + and files (larger than 4GB), full uid/gid information, hard links and 14 14 timestamps. 15 15 16 16 Squashfs is intended for general read-only filesystem use, for
+34
fs/squashfs/decompressor.c
··· 23 23 24 24 #include <linux/types.h> 25 25 #include <linux/mutex.h> 26 + #include <linux/slab.h> 26 27 #include <linux/buffer_head.h> 27 28 28 29 #include "squashfs_fs.h" ··· 74 73 break; 75 74 76 75 return decompressor[i]; 76 + } 77 + 78 + 79 + void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) 80 + { 81 + struct squashfs_sb_info *msblk = sb->s_fs_info; 82 + void *strm, *buffer = NULL; 83 + int length = 0; 84 + 85 + /* 86 + * Read decompressor specific options from file system if present 87 + */ 88 + if (SQUASHFS_COMP_OPTS(flags)) { 89 + buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); 90 + if (buffer == NULL) 91 + return ERR_PTR(-ENOMEM); 92 + 93 + length = squashfs_read_data(sb, &buffer, 94 + sizeof(struct squashfs_super_block), 0, NULL, 95 + PAGE_CACHE_SIZE, 1); 96 + 97 + if (length < 0) { 98 + strm = ERR_PTR(length); 99 + goto finished; 100 + } 101 + } 102 + 103 + strm = msblk->decompressor->init(msblk, buffer, length); 104 + 105 + finished: 106 + kfree(buffer); 107 + 108 + return strm; 77 109 }
+1 -6
fs/squashfs/decompressor.h
··· 24 24 */ 25 25 26 26 struct squashfs_decompressor { 27 - void *(*init)(struct squashfs_sb_info *); 27 + void *(*init)(struct squashfs_sb_info *, void *, int); 28 28 void (*free)(void *); 29 29 int (*decompress)(struct squashfs_sb_info *, void **, 30 30 struct buffer_head **, int, int, int, int, int); ··· 32 32 char *name; 33 33 int supported; 34 34 }; 35 - 36 - static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk) 37 - { 38 - return msblk->decompressor->init(msblk); 39 - } 40 35 41 36 static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, 42 37 void *s)
+9
fs/squashfs/dir.c
··· 172 172 length += sizeof(dirh); 173 173 174 174 dir_count = le32_to_cpu(dirh.count) + 1; 175 + 176 + /* dir_count should never be larger than 256 */ 177 + if (dir_count > 256) 178 + goto failed_read; 179 + 175 180 while (dir_count--) { 176 181 /* 177 182 * Read directory entry. ··· 187 182 goto failed_read; 188 183 189 184 size = le16_to_cpu(dire->size) + 1; 185 + 186 + /* size should never be larger than SQUASHFS_NAME_LEN */ 187 + if (size > SQUASHFS_NAME_LEN) 188 + goto failed_read; 190 189 191 190 err = squashfs_read_metadata(inode->i_sb, dire->name, 192 191 &block, &offset, size);
+2 -2
fs/squashfs/lzo_wrapper.c
··· 37 37 void *output; 38 38 }; 39 39 40 - static void *lzo_init(struct squashfs_sb_info *msblk) 40 + static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len) 41 41 { 42 42 int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); 43 43 ··· 58 58 failed: 59 59 ERROR("Failed to allocate lzo workspace\n"); 60 60 kfree(stream); 61 - return NULL; 61 + return ERR_PTR(-ENOMEM); 62 62 } 63 63 64 64
+12
fs/squashfs/namei.c
··· 176 176 length += sizeof(dirh); 177 177 178 178 dir_count = le32_to_cpu(dirh.count) + 1; 179 + 180 + /* dir_count should never be larger than 256 */ 181 + if (dir_count > 256) 182 + goto data_error; 183 + 179 184 while (dir_count--) { 180 185 /* 181 186 * Read directory entry. ··· 191 186 goto read_failure; 192 187 193 188 size = le16_to_cpu(dire->size) + 1; 189 + 190 + /* size should never be larger than SQUASHFS_NAME_LEN */ 191 + if (size > SQUASHFS_NAME_LEN) 192 + goto data_error; 194 193 195 194 err = squashfs_read_metadata(dir->i_sb, dire->name, 196 195 &block, &offset, size); ··· 236 227 return d_splice_alias(inode, dentry); 237 228 d_add(dentry, inode); 238 229 return ERR_PTR(0); 230 + 231 + data_error: 232 + err = -EIO; 239 233 240 234 read_failure: 241 235 ERROR("Unable to read directory block [%llx:%x]\n",
+1
fs/squashfs/squashfs.h
··· 48 48 49 49 /* decompressor.c */ 50 50 extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); 51 + extern void *squashfs_decompressor_init(struct super_block *, unsigned short); 51 52 52 53 /* export.c */ 53 54 extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
+4
fs/squashfs/squashfs_fs.h
··· 57 57 #define SQUASHFS_ALWAYS_FRAG 5 58 58 #define SQUASHFS_DUPLICATE 6 59 59 #define SQUASHFS_EXPORT 7 60 + #define SQUASHFS_COMP_OPT 10 60 61 61 62 #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) 62 63 ··· 81 80 82 81 #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ 83 82 SQUASHFS_EXPORT) 83 + 84 + #define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \ 85 + SQUASHFS_COMP_OPT) 84 86 85 87 /* Max number of types and file types */ 86 88 #define SQUASHFS_DIR_TYPE 1
+9 -6
fs/squashfs/super.c
··· 199 199 200 200 err = -ENOMEM; 201 201 202 - msblk->stream = squashfs_decompressor_init(msblk); 203 - if (msblk->stream == NULL) 204 - goto failed_mount; 205 - 206 202 msblk->block_cache = squashfs_cache_init("metadata", 207 203 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); 208 204 if (msblk->block_cache == NULL) ··· 208 212 msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size); 209 213 if (msblk->read_page == NULL) { 210 214 ERROR("Failed to allocate read_page block\n"); 215 + goto failed_mount; 216 + } 217 + 218 + msblk->stream = squashfs_decompressor_init(sb, flags); 219 + if (IS_ERR(msblk->stream)) { 220 + err = PTR_ERR(msblk->stream); 221 + msblk->stream = NULL; 211 222 goto failed_mount; 212 223 } 213 224 ··· 373 370 } 374 371 375 372 376 - static struct dentry *squashfs_mount(struct file_system_type *fs_type, int flags, 377 - const char *dev_name, void *data) 373 + static struct dentry *squashfs_mount(struct file_system_type *fs_type, 374 + int flags, const char *dev_name, void *data) 378 375 { 379 376 return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); 380 377 }
+44 -11
fs/squashfs/xz_wrapper.c
··· 26 26 #include <linux/buffer_head.h> 27 27 #include <linux/slab.h> 28 28 #include <linux/xz.h> 29 + #include <linux/bitops.h> 29 30 30 31 #include "squashfs_fs.h" 31 32 #include "squashfs_fs_sb.h" 32 - #include "squashfs_fs_i.h" 33 33 #include "squashfs.h" 34 34 #include "decompressor.h" 35 35 ··· 38 38 struct xz_buf buf; 39 39 }; 40 40 41 - static void *squashfs_xz_init(struct squashfs_sb_info *msblk) 41 + struct comp_opts { 42 + __le32 dictionary_size; 43 + __le32 flags; 44 + }; 45 + 46 + static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, 47 + int len) 42 48 { 43 - int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); 49 + struct comp_opts *comp_opts = buff; 50 + struct squashfs_xz *stream; 51 + int dict_size = msblk->block_size; 52 + int err, n; 44 53 45 - struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL); 46 - if (stream == NULL) 47 - goto failed; 54 + if (comp_opts) { 55 + /* check compressor options are the expected length */ 56 + if (len < sizeof(*comp_opts)) { 57 + err = -EIO; 58 + goto failed; 59 + } 48 60 49 - stream->state = xz_dec_init(XZ_PREALLOC, block_size); 50 - if (stream->state == NULL) 61 + dict_size = le32_to_cpu(comp_opts->dictionary_size); 62 + 63 + /* the dictionary size should be 2^n or 2^n+2^(n+1) */ 64 + n = ffs(dict_size) - 1; 65 + if (dict_size != (1 << n) && dict_size != (1 << n) + 66 + (1 << (n + 1))) { 67 + err = -EIO; 68 + goto failed; 69 + } 70 + } 71 + 72 + dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); 73 + 74 + stream = kmalloc(sizeof(*stream), GFP_KERNEL); 75 + if (stream == NULL) { 76 + err = -ENOMEM; 51 77 goto failed; 78 + } 79 + 80 + stream->state = xz_dec_init(XZ_PREALLOC, dict_size); 81 + if (stream->state == NULL) { 82 + kfree(stream); 83 + err = -ENOMEM; 84 + goto failed; 85 + } 52 86 53 87 return stream; 54 88 55 89 failed: 56 - ERROR("Failed to allocate xz workspace\n"); 57 - kfree(stream); 58 - return NULL; 90 + ERROR("Failed to initialise xz decompressor\n"); 91 + return ERR_PTR(err); 59 92 } 60 93 61 94
+5 -5
fs/squashfs/zlib_wrapper.c
··· 26 26 #include <linux/buffer_head.h> 27 27 #include <linux/slab.h> 28 28 #include <linux/zlib.h> 29 + #include <linux/vmalloc.h> 29 30 30 31 #include "squashfs_fs.h" 31 32 #include "squashfs_fs_sb.h" 32 33 #include "squashfs.h" 33 34 #include "decompressor.h" 34 35 35 - static void *zlib_init(struct squashfs_sb_info *dummy) 36 + static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len) 36 37 { 37 38 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); 38 39 if (stream == NULL) 39 40 goto failed; 40 - stream->workspace = kmalloc(zlib_inflate_workspacesize(), 41 - GFP_KERNEL); 41 + stream->workspace = vmalloc(zlib_inflate_workspacesize()); 42 42 if (stream->workspace == NULL) 43 43 goto failed; 44 44 ··· 47 47 failed: 48 48 ERROR("Failed to allocate zlib workspace\n"); 49 49 kfree(stream); 50 - return NULL; 50 + return ERR_PTR(-ENOMEM); 51 51 } 52 52 53 53 ··· 56 56 z_stream *stream = strm; 57 57 58 58 if (stream) 59 - kfree(stream->workspace); 59 + vfree(stream->workspace); 60 60 kfree(stream); 61 61 } 62 62