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: 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

+723 -24
+27 -5
Documentation/filesystems/squashfs.txt
··· 38 Real inode numbers: yes no 39 32-bit uids/gids: yes no 40 File creation time: yes no 41 - Xattr and ACL support: no no 42 43 Squashfs compresses data, inodes and directories. In addition, inode and 44 directory data are highly compacted, and packed on byte boundaries. Each ··· 59 3. SQUASHFS FILESYSTEM DESIGN 60 ----------------------------- 61 62 - A squashfs filesystem consists of seven parts, packed together on a byte 63 alignment: 64 65 --------------- ··· 81 |---------------| 82 | uid/gid | 83 | lookup table | 84 --------------- 85 86 Compressed data blocks are written to the filesystem as files are read from ··· 196 used to locate these. This second index table for speed of access (and because 197 it is small) is read at mount time and cached in memory. 198 199 200 4. TODOS AND OUTSTANDING ISSUES 201 ------------------------------- ··· 223 4.1 Todo list 224 ------------- 225 226 - Implement Xattr and ACL support. The Squashfs 4.0 filesystem layout has hooks 227 - for these but the code has not been written. Once the code has been written 228 - the existing layout should not require modification. 229 230 4.2 Squashfs internal cache 231 ---------------------------
··· 38 Real inode numbers: yes no 39 32-bit uids/gids: yes no 40 File creation time: yes no 41 + Xattr support: yes no 42 + ACL support: no no 43 44 Squashfs compresses data, inodes and directories. In addition, inode and 45 directory data are highly compacted, and packed on byte boundaries. Each ··· 58 3. SQUASHFS FILESYSTEM DESIGN 59 ----------------------------- 60 61 + A squashfs filesystem consists of a maximum of eight parts, packed together on a byte 62 alignment: 63 64 --------------- ··· 80 |---------------| 81 | uid/gid | 82 | lookup table | 83 + |---------------| 84 + | xattr | 85 + | table | 86 --------------- 87 88 Compressed data blocks are written to the filesystem as files are read from ··· 192 used to locate these. This second index table for speed of access (and because 193 it is small) is read at mount time and cached in memory. 194 195 + 3.7 Xattr table 196 + --------------- 197 + 198 + The xattr table contains extended attributes for each inode. The xattrs 199 + for each inode are stored in a list, each list entry containing a type, 200 + name and value field. The type field encodes the xattr prefix 201 + ("user.", "trusted." etc) and it also encodes how the name/value fields 202 + should be interpreted. Currently the type indicates whether the value 203 + is stored inline (in which case the value field contains the xattr value), 204 + or if it is stored out of line (in which case the value field stores a 205 + reference to where the actual value is stored). This allows large values 206 + to be stored out of line improving scanning and lookup performance and it 207 + also allows values to be de-duplicated, the value being stored once, and 208 + all other occurences holding an out of line reference to that value. 209 + 210 + The xattr lists are packed into compressed 8K metadata blocks. 211 + To reduce overhead in inodes, rather than storing the on-disk 212 + location of the xattr list inside each inode, a 32-bit xattr id 213 + is stored. This xattr id is mapped into the location of the xattr 214 + list using a second xattr id lookup table. 215 216 4. TODOS AND OUTSTANDING ISSUES 217 ------------------------------- ··· 199 4.1 Todo list 200 ------------- 201 202 + Implement ACL support. 203 204 4.2 Squashfs internal cache 205 ---------------------------
+11
fs/squashfs/Kconfig
··· 26 27 If unsure, say N. 28 29 config SQUASHFS_EMBEDDED 30 31 bool "Additional option for memory-constrained systems"
··· 26 27 If unsure, say N. 28 29 + config SQUASHFS_XATTRS 30 + bool "Squashfs XATTR support" 31 + depends on SQUASHFS 32 + default n 33 + help 34 + Saying Y here includes support for extended attributes (xattrs). 35 + Xattrs are name:value pairs associated with inodes by 36 + the kernel or by users (see the attr(5) manual page). 37 + 38 + If unsure, say N. 39 + 40 config SQUASHFS_EMBEDDED 41 42 bool "Additional option for memory-constrained systems"
+2
fs/squashfs/Makefile
··· 5 obj-$(CONFIG_SQUASHFS) += squashfs.o 6 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 7 squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
··· 5 obj-$(CONFIG_SQUASHFS) += squashfs.o 6 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 7 squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o 8 + squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o 9 +
+85 -7
fs/squashfs/inode.c
··· 40 41 #include <linux/fs.h> 42 #include <linux/vfs.h> 43 44 #include "squashfs_fs.h" 45 #include "squashfs_fs_sb.h" 46 #include "squashfs_fs_i.h" 47 #include "squashfs.h" 48 49 /* 50 * Initialise VFS inode with the base inode information common to all ··· 113 int err, type, offset = SQUASHFS_INODE_OFFSET(ino); 114 union squashfs_inode squashfs_ino; 115 struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; 116 117 TRACE("Entered squashfs_read_inode\n"); 118 ··· 202 frag_offset = 0; 203 } 204 205 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 206 inode->i_size = le64_to_cpu(sqsh_ino->file_size); 207 inode->i_fop = &generic_ro_fops; 208 inode->i_mode |= S_IFREG; 209 inode->i_blocks = ((inode->i_size - ··· 256 if (err < 0) 257 goto failed_read; 258 259 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 260 inode->i_size = le32_to_cpu(sqsh_ino->file_size); 261 inode->i_op = &squashfs_dir_inode_ops; ··· 286 287 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 288 inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); 289 - inode->i_op = &page_symlink_inode_operations; 290 inode->i_data.a_ops = &squashfs_symlink_aops; 291 inode->i_mode |= S_IFLNK; 292 squashfs_i(inode)->start = block; 293 squashfs_i(inode)->offset = offset; 294 295 TRACE("Symbolic link inode %x:%x, start_block %llx, offset " 296 "%x\n", SQUASHFS_INODE_BLK(ino), offset, ··· 312 break; 313 } 314 case SQUASHFS_BLKDEV_TYPE: 315 - case SQUASHFS_CHRDEV_TYPE: 316 - case SQUASHFS_LBLKDEV_TYPE: 317 - case SQUASHFS_LCHRDEV_TYPE: { 318 struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; 319 unsigned int rdev; 320 ··· 333 SQUASHFS_INODE_BLK(ino), offset, rdev); 334 break; 335 } 336 case SQUASHFS_FIFO_TYPE: 337 - case SQUASHFS_SOCKET_TYPE: 338 - case SQUASHFS_LFIFO_TYPE: 339 - case SQUASHFS_LSOCKET_TYPE: { 340 struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; 341 342 err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, ··· 374 init_special_inode(inode, inode->i_mode, 0); 375 break; 376 } 377 default: 378 ERROR("Unknown inode type %d in squashfs_iget!\n", type); 379 return -EINVAL; 380 } 381 382 return 0; 383 ··· 416 ERROR("Unable to read inode 0x%llx\n", ino); 417 return err; 418 }
··· 40 41 #include <linux/fs.h> 42 #include <linux/vfs.h> 43 + #include <linux/xattr.h> 44 45 #include "squashfs_fs.h" 46 #include "squashfs_fs_sb.h" 47 #include "squashfs_fs_i.h" 48 #include "squashfs.h" 49 + #include "xattr.h" 50 51 /* 52 * Initialise VFS inode with the base inode information common to all ··· 111 int err, type, offset = SQUASHFS_INODE_OFFSET(ino); 112 union squashfs_inode squashfs_ino; 113 struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; 114 + int xattr_id = SQUASHFS_INVALID_XATTR; 115 116 TRACE("Entered squashfs_read_inode\n"); 117 ··· 199 frag_offset = 0; 200 } 201 202 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 203 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 204 inode->i_size = le64_to_cpu(sqsh_ino->file_size); 205 + inode->i_op = &squashfs_inode_ops; 206 inode->i_fop = &generic_ro_fops; 207 inode->i_mode |= S_IFREG; 208 inode->i_blocks = ((inode->i_size - ··· 251 if (err < 0) 252 goto failed_read; 253 254 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 255 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 256 inode->i_size = le32_to_cpu(sqsh_ino->file_size); 257 inode->i_op = &squashfs_dir_inode_ops; ··· 280 281 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 282 inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); 283 + inode->i_op = &squashfs_symlink_inode_ops; 284 inode->i_data.a_ops = &squashfs_symlink_aops; 285 inode->i_mode |= S_IFLNK; 286 squashfs_i(inode)->start = block; 287 squashfs_i(inode)->offset = offset; 288 + 289 + if (type == SQUASHFS_LSYMLINK_TYPE) { 290 + __le32 xattr; 291 + 292 + err = squashfs_read_metadata(sb, NULL, &block, 293 + &offset, inode->i_size); 294 + if (err < 0) 295 + goto failed_read; 296 + err = squashfs_read_metadata(sb, &xattr, &block, 297 + &offset, sizeof(xattr)); 298 + if (err < 0) 299 + goto failed_read; 300 + xattr_id = le32_to_cpu(xattr); 301 + } 302 303 TRACE("Symbolic link inode %x:%x, start_block %llx, offset " 304 "%x\n", SQUASHFS_INODE_BLK(ino), offset, ··· 292 break; 293 } 294 case SQUASHFS_BLKDEV_TYPE: 295 + case SQUASHFS_CHRDEV_TYPE: { 296 struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; 297 unsigned int rdev; 298 ··· 315 SQUASHFS_INODE_BLK(ino), offset, rdev); 316 break; 317 } 318 + case SQUASHFS_LBLKDEV_TYPE: 319 + case SQUASHFS_LCHRDEV_TYPE: { 320 + struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev; 321 + unsigned int rdev; 322 + 323 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, 324 + sizeof(*sqsh_ino)); 325 + if (err < 0) 326 + goto failed_read; 327 + 328 + if (type == SQUASHFS_LCHRDEV_TYPE) 329 + inode->i_mode |= S_IFCHR; 330 + else 331 + inode->i_mode |= S_IFBLK; 332 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 333 + inode->i_op = &squashfs_inode_ops; 334 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 335 + rdev = le32_to_cpu(sqsh_ino->rdev); 336 + init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); 337 + 338 + TRACE("Device inode %x:%x, rdev %x\n", 339 + SQUASHFS_INODE_BLK(ino), offset, rdev); 340 + break; 341 + } 342 case SQUASHFS_FIFO_TYPE: 343 + case SQUASHFS_SOCKET_TYPE: { 344 struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; 345 346 err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, ··· 334 init_special_inode(inode, inode->i_mode, 0); 335 break; 336 } 337 + case SQUASHFS_LFIFO_TYPE: 338 + case SQUASHFS_LSOCKET_TYPE: { 339 + struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc; 340 + 341 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, 342 + sizeof(*sqsh_ino)); 343 + if (err < 0) 344 + goto failed_read; 345 + 346 + if (type == SQUASHFS_LFIFO_TYPE) 347 + inode->i_mode |= S_IFIFO; 348 + else 349 + inode->i_mode |= S_IFSOCK; 350 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 351 + inode->i_op = &squashfs_inode_ops; 352 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 353 + init_special_inode(inode, inode->i_mode, 0); 354 + break; 355 + } 356 default: 357 ERROR("Unknown inode type %d in squashfs_iget!\n", type); 358 return -EINVAL; 359 } 360 + 361 + if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) { 362 + err = squashfs_xattr_lookup(sb, xattr_id, 363 + &squashfs_i(inode)->xattr_count, 364 + &squashfs_i(inode)->xattr_size, 365 + &squashfs_i(inode)->xattr); 366 + if (err < 0) 367 + goto failed_read; 368 + inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9) 369 + + 1; 370 + } else 371 + squashfs_i(inode)->xattr_count = 0; 372 373 return 0; 374 ··· 345 ERROR("Unable to read inode 0x%llx\n", ino); 346 return err; 347 } 348 + 349 + 350 + const struct inode_operations squashfs_inode_ops = { 351 + .getxattr = generic_getxattr, 352 + .listxattr = squashfs_listxattr 353 + }; 354 +
+5 -1
fs/squashfs/namei.c
··· 57 #include <linux/slab.h> 58 #include <linux/string.h> 59 #include <linux/dcache.h> 60 61 #include "squashfs_fs.h" 62 #include "squashfs_fs_sb.h" 63 #include "squashfs_fs_i.h" 64 #include "squashfs.h" 65 66 /* 67 * Lookup name in the directory index, returning the location of the metadata ··· 239 240 241 const struct inode_operations squashfs_dir_inode_ops = { 242 - .lookup = squashfs_lookup 243 };
··· 57 #include <linux/slab.h> 58 #include <linux/string.h> 59 #include <linux/dcache.h> 60 + #include <linux/xattr.h> 61 62 #include "squashfs_fs.h" 63 #include "squashfs_fs_sb.h" 64 #include "squashfs_fs_i.h" 65 #include "squashfs.h" 66 + #include "xattr.h" 67 68 /* 69 * Lookup name in the directory index, returning the location of the metadata ··· 237 238 239 const struct inode_operations squashfs_dir_inode_ops = { 240 + .lookup = squashfs_lookup, 241 + .getxattr = generic_getxattr, 242 + .listxattr = squashfs_listxattr 243 };
+11 -1
fs/squashfs/squashfs.h
··· 73 unsigned int); 74 extern int squashfs_read_inode(struct inode *, long long); 75 76 /* 77 - * Inodes, files and decompressor operations 78 */ 79 80 /* dir.c */ ··· 89 /* file.c */ 90 extern const struct address_space_operations squashfs_aops; 91 92 /* namei.c */ 93 extern const struct inode_operations squashfs_dir_inode_ops; 94 95 /* symlink.c */ 96 extern const struct address_space_operations squashfs_symlink_aops; 97 98 /* zlib_wrapper.c */ 99 extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
··· 73 unsigned int); 74 extern int squashfs_read_inode(struct inode *, long long); 75 76 + /* xattr.c */ 77 + extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t); 78 + 79 /* 80 + * Inodes, files, decompressor and xattr operations 81 */ 82 83 /* dir.c */ ··· 86 /* file.c */ 87 extern const struct address_space_operations squashfs_aops; 88 89 + /* inode.c */ 90 + extern const struct inode_operations squashfs_inode_ops; 91 + 92 /* namei.c */ 93 extern const struct inode_operations squashfs_dir_inode_ops; 94 95 /* symlink.c */ 96 extern const struct address_space_operations squashfs_symlink_aops; 97 + extern const struct inode_operations squashfs_symlink_inode_ops; 98 + 99 + /* xattr.c */ 100 + extern const struct xattr_handler *squashfs_xattr_handlers[]; 101 102 /* zlib_wrapper.c */ 103 extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
+75 -1
fs/squashfs/squashfs_fs.h
··· 46 #define SQUASHFS_NAME_LEN 256 47 48 #define SQUASHFS_INVALID_FRAG (0xffffffffU) 49 #define SQUASHFS_INVALID_BLK (-1LL) 50 51 /* Filesystem flags */ ··· 96 #define SQUASHFS_LCHRDEV_TYPE 12 97 #define SQUASHFS_LFIFO_TYPE 13 98 #define SQUASHFS_LSOCKET_TYPE 14 99 100 /* Flag whether block is compressed or uncompressed, bit is set if block is 101 * uncompressed */ ··· 182 183 #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ 184 sizeof(u64)) 185 186 /* cached data constants for filesystem */ 187 #define SQUASHFS_CACHED_BLKS 8 ··· 254 __le64 root_inode; 255 __le64 bytes_used; 256 __le64 id_table_start; 257 - __le64 xattr_table_start; 258 __le64 inode_table_start; 259 __le64 directory_table_start; 260 __le64 fragment_table_start; ··· 287 __le32 nlink; 288 }; 289 290 struct squashfs_dev_inode { 291 __le16 inode_type; 292 __le16 mode; ··· 307 __le32 inode_number; 308 __le32 nlink; 309 __le32 rdev; 310 }; 311 312 struct squashfs_symlink_inode { ··· 398 union squashfs_inode { 399 struct squashfs_base_inode base; 400 struct squashfs_dev_inode dev; 401 struct squashfs_symlink_inode symlink; 402 struct squashfs_reg_inode reg; 403 struct squashfs_lreg_inode lreg; 404 struct squashfs_dir_inode dir; 405 struct squashfs_ldir_inode ldir; 406 struct squashfs_ipc_inode ipc; 407 }; 408 409 struct squashfs_dir_entry { ··· 426 __le64 start_block; 427 __le32 size; 428 unsigned int unused; 429 }; 430 431 #endif
··· 46 #define SQUASHFS_NAME_LEN 256 47 48 #define SQUASHFS_INVALID_FRAG (0xffffffffU) 49 + #define SQUASHFS_INVALID_XATTR (0xffffffffU) 50 #define SQUASHFS_INVALID_BLK (-1LL) 51 52 /* Filesystem flags */ ··· 95 #define SQUASHFS_LCHRDEV_TYPE 12 96 #define SQUASHFS_LFIFO_TYPE 13 97 #define SQUASHFS_LSOCKET_TYPE 14 98 + 99 + /* Xattr types */ 100 + #define SQUASHFS_XATTR_USER 0 101 + #define SQUASHFS_XATTR_TRUSTED 1 102 + #define SQUASHFS_XATTR_SECURITY 2 103 + #define SQUASHFS_XATTR_VALUE_OOL 256 104 + #define SQUASHFS_XATTR_PREFIX_MASK 0xff 105 106 /* Flag whether block is compressed or uncompressed, bit is set if block is 107 * uncompressed */ ··· 174 175 #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ 176 sizeof(u64)) 177 + /* xattr id lookup table defines */ 178 + #define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id)) 179 + 180 + #define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \ 181 + SQUASHFS_METADATA_SIZE) 182 + 183 + #define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \ 184 + SQUASHFS_METADATA_SIZE) 185 + 186 + #define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \ 187 + SQUASHFS_METADATA_SIZE - 1) / \ 188 + SQUASHFS_METADATA_SIZE) 189 + 190 + #define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\ 191 + sizeof(u64)) 192 + #define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16)) 193 + 194 + #define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff)) 195 196 /* cached data constants for filesystem */ 197 #define SQUASHFS_CACHED_BLKS 8 ··· 228 __le64 root_inode; 229 __le64 bytes_used; 230 __le64 id_table_start; 231 + __le64 xattr_id_table_start; 232 __le64 inode_table_start; 233 __le64 directory_table_start; 234 __le64 fragment_table_start; ··· 261 __le32 nlink; 262 }; 263 264 + struct squashfs_lipc_inode { 265 + __le16 inode_type; 266 + __le16 mode; 267 + __le16 uid; 268 + __le16 guid; 269 + __le32 mtime; 270 + __le32 inode_number; 271 + __le32 nlink; 272 + __le32 xattr; 273 + }; 274 + 275 struct squashfs_dev_inode { 276 __le16 inode_type; 277 __le16 mode; ··· 270 __le32 inode_number; 271 __le32 nlink; 272 __le32 rdev; 273 + }; 274 + 275 + struct squashfs_ldev_inode { 276 + __le16 inode_type; 277 + __le16 mode; 278 + __le16 uid; 279 + __le16 guid; 280 + __le32 mtime; 281 + __le32 inode_number; 282 + __le32 nlink; 283 + __le32 rdev; 284 + __le32 xattr; 285 }; 286 287 struct squashfs_symlink_inode { ··· 349 union squashfs_inode { 350 struct squashfs_base_inode base; 351 struct squashfs_dev_inode dev; 352 + struct squashfs_ldev_inode ldev; 353 struct squashfs_symlink_inode symlink; 354 struct squashfs_reg_inode reg; 355 struct squashfs_lreg_inode lreg; 356 struct squashfs_dir_inode dir; 357 struct squashfs_ldir_inode ldir; 358 struct squashfs_ipc_inode ipc; 359 + struct squashfs_lipc_inode lipc; 360 }; 361 362 struct squashfs_dir_entry { ··· 375 __le64 start_block; 376 __le32 size; 377 unsigned int unused; 378 + }; 379 + 380 + struct squashfs_xattr_entry { 381 + __le16 type; 382 + __le16 size; 383 + char data[0]; 384 + }; 385 + 386 + struct squashfs_xattr_val { 387 + __le32 vsize; 388 + char value[0]; 389 + }; 390 + 391 + struct squashfs_xattr_id { 392 + __le64 xattr; 393 + __le32 count; 394 + __le32 size; 395 + }; 396 + 397 + struct squashfs_xattr_id_table { 398 + __le64 xattr_table_start; 399 + __le32 xattr_ids; 400 + __le32 unused; 401 }; 402 403 #endif
+3
fs/squashfs/squashfs_fs_i.h
··· 26 struct squashfs_inode_info { 27 u64 start; 28 int offset; 29 union { 30 struct { 31 u64 fragment_block;
··· 26 struct squashfs_inode_info { 27 u64 start; 28 int offset; 29 + u64 xattr; 30 + unsigned int xattr_size; 31 + int xattr_count; 32 union { 33 struct { 34 u64 fragment_block;
+3
fs/squashfs/squashfs_fs_sb.h
··· 61 int next_meta_index; 62 __le64 *id_table; 63 __le64 *fragment_index; 64 struct mutex read_data_mutex; 65 struct mutex meta_index_mutex; 66 struct meta_index *meta_index; ··· 69 __le64 *inode_lookup_table; 70 u64 inode_table; 71 u64 directory_table; 72 unsigned int block_size; 73 unsigned short block_log; 74 long long bytes_used; 75 unsigned int inodes; 76 }; 77 #endif
··· 61 int next_meta_index; 62 __le64 *id_table; 63 __le64 *fragment_index; 64 + __le64 *xattr_id_table; 65 struct mutex read_data_mutex; 66 struct mutex meta_index_mutex; 67 struct meta_index *meta_index; ··· 68 __le64 *inode_lookup_table; 69 u64 inode_table; 70 u64 directory_table; 71 + u64 xattr_table; 72 unsigned int block_size; 73 unsigned short block_log; 74 long long bytes_used; 75 unsigned int inodes; 76 + int xattr_ids; 77 }; 78 #endif
+21 -9
fs/squashfs/super.c
··· 36 #include <linux/init.h> 37 #include <linux/module.h> 38 #include <linux/magic.h> 39 40 #include "squashfs_fs.h" 41 #include "squashfs_fs_sb.h" 42 #include "squashfs_fs_i.h" 43 #include "squashfs.h" 44 #include "decompressor.h" 45 46 static struct file_system_type squashfs_fs_type; 47 static const struct super_operations squashfs_super_ops; ··· 84 long long root_inode; 85 unsigned short flags; 86 unsigned int fragments; 87 - u64 lookup_table_start; 88 int err; 89 90 TRACE("Entered squashfs_fill_superblock\n"); ··· 140 le16_to_cpu(sblk->compression)); 141 if (msblk->decompressor == NULL) 142 goto failed_mount; 143 - 144 - /* 145 - * Check if there's xattrs in the filesystem. These are not 146 - * supported in this version, so warn that they will be ignored. 147 - */ 148 - if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK) 149 - ERROR("Xattrs in filesystem, these will be ignored\n"); 150 151 /* Check the filesystem does not extend beyond the end of the 152 block device */ ··· 248 allocate_lookup_table: 249 lookup_table_start = le64_to_cpu(sblk->lookup_table_start); 250 if (lookup_table_start == SQUASHFS_INVALID_BLK) 251 - goto allocate_root; 252 253 /* Allocate and read inode lookup table */ 254 msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, ··· 261 262 sb->s_export_op = &squashfs_export_ops; 263 264 allocate_root: 265 root = new_inode(sb); 266 if (!root) { ··· 311 kfree(msblk->inode_lookup_table); 312 kfree(msblk->fragment_index); 313 kfree(msblk->id_table); 314 kfree(sb->s_fs_info); 315 sb->s_fs_info = NULL; 316 kfree(sblk); ··· 366 kfree(sbi->fragment_index); 367 kfree(sbi->meta_index); 368 kfree(sbi->inode_lookup_table); 369 kfree(sb->s_fs_info); 370 sb->s_fs_info = NULL; 371 }
··· 36 #include <linux/init.h> 37 #include <linux/module.h> 38 #include <linux/magic.h> 39 + #include <linux/xattr.h> 40 41 #include "squashfs_fs.h" 42 #include "squashfs_fs_sb.h" 43 #include "squashfs_fs_i.h" 44 #include "squashfs.h" 45 #include "decompressor.h" 46 + #include "xattr.h" 47 48 static struct file_system_type squashfs_fs_type; 49 static const struct super_operations squashfs_super_ops; ··· 82 long long root_inode; 83 unsigned short flags; 84 unsigned int fragments; 85 + u64 lookup_table_start, xattr_id_table_start; 86 int err; 87 88 TRACE("Entered squashfs_fill_superblock\n"); ··· 138 le16_to_cpu(sblk->compression)); 139 if (msblk->decompressor == NULL) 140 goto failed_mount; 141 142 /* Check the filesystem does not extend beyond the end of the 143 block device */ ··· 253 allocate_lookup_table: 254 lookup_table_start = le64_to_cpu(sblk->lookup_table_start); 255 if (lookup_table_start == SQUASHFS_INVALID_BLK) 256 + goto allocate_xattr_table; 257 258 /* Allocate and read inode lookup table */ 259 msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, ··· 266 267 sb->s_export_op = &squashfs_export_ops; 268 269 + allocate_xattr_table: 270 + sb->s_xattr = squashfs_xattr_handlers; 271 + xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); 272 + if (xattr_id_table_start == SQUASHFS_INVALID_BLK) 273 + goto allocate_root; 274 + 275 + /* Allocate and read xattr id lookup table */ 276 + msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, 277 + xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); 278 + if (IS_ERR(msblk->xattr_id_table)) { 279 + err = PTR_ERR(msblk->xattr_id_table); 280 + msblk->xattr_id_table = NULL; 281 + if (err != -ENOTSUPP) 282 + goto failed_mount; 283 + } 284 allocate_root: 285 root = new_inode(sb); 286 if (!root) { ··· 301 kfree(msblk->inode_lookup_table); 302 kfree(msblk->fragment_index); 303 kfree(msblk->id_table); 304 + kfree(msblk->xattr_id_table); 305 kfree(sb->s_fs_info); 306 sb->s_fs_info = NULL; 307 kfree(sblk); ··· 355 kfree(sbi->fragment_index); 356 kfree(sbi->meta_index); 357 kfree(sbi->inode_lookup_table); 358 + kfree(sbi->xattr_id_table); 359 kfree(sb->s_fs_info); 360 sb->s_fs_info = NULL; 361 }
+11
fs/squashfs/symlink.c
··· 35 #include <linux/kernel.h> 36 #include <linux/string.h> 37 #include <linux/pagemap.h> 38 39 #include "squashfs_fs.h" 40 #include "squashfs_fs_sb.h" 41 #include "squashfs_fs_i.h" 42 #include "squashfs.h" 43 44 static int squashfs_symlink_readpage(struct file *file, struct page *page) 45 { ··· 116 const struct address_space_operations squashfs_symlink_aops = { 117 .readpage = squashfs_symlink_readpage 118 };
··· 35 #include <linux/kernel.h> 36 #include <linux/string.h> 37 #include <linux/pagemap.h> 38 + #include <linux/xattr.h> 39 40 #include "squashfs_fs.h" 41 #include "squashfs_fs_sb.h" 42 #include "squashfs_fs_i.h" 43 #include "squashfs.h" 44 + #include "xattr.h" 45 46 static int squashfs_symlink_readpage(struct file *file, struct page *page) 47 { ··· 114 const struct address_space_operations squashfs_symlink_aops = { 115 .readpage = squashfs_symlink_readpage 116 }; 117 + 118 + const struct inode_operations squashfs_symlink_inode_ops = { 119 + .readlink = generic_readlink, 120 + .follow_link = page_follow_link_light, 121 + .put_link = page_put_link, 122 + .getxattr = generic_getxattr, 123 + .listxattr = squashfs_listxattr 124 + }; 125 +
+323
fs/squashfs/xattr.c
···
··· 1 + /* 2 + * Squashfs - a compressed read only filesystem for Linux 3 + * 4 + * Copyright (c) 2010 5 + * Phillip Lougher <phillip@lougher.demon.co.uk> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * as published by the Free Software Foundation; either version 2, 10 + * or (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License 18 + * along with this program; if not, write to the Free Software 19 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 + * 21 + * xattr_id.c 22 + */ 23 + 24 + #include <linux/init.h> 25 + #include <linux/module.h> 26 + #include <linux/string.h> 27 + #include <linux/fs.h> 28 + #include <linux/vfs.h> 29 + #include <linux/xattr.h> 30 + #include <linux/slab.h> 31 + 32 + #include "squashfs_fs.h" 33 + #include "squashfs_fs_sb.h" 34 + #include "squashfs_fs_i.h" 35 + #include "squashfs.h" 36 + 37 + static const struct xattr_handler *squashfs_xattr_handler(int); 38 + 39 + ssize_t squashfs_listxattr(struct dentry *d, char *buffer, 40 + size_t buffer_size) 41 + { 42 + struct inode *inode = d->d_inode; 43 + struct super_block *sb = inode->i_sb; 44 + struct squashfs_sb_info *msblk = sb->s_fs_info; 45 + u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) 46 + + msblk->xattr_table; 47 + int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); 48 + int count = squashfs_i(inode)->xattr_count; 49 + size_t rest = buffer_size; 50 + int err; 51 + 52 + /* check that the file system has xattrs */ 53 + if (msblk->xattr_id_table == NULL) 54 + return -EOPNOTSUPP; 55 + 56 + /* loop reading each xattr name */ 57 + while (count--) { 58 + struct squashfs_xattr_entry entry; 59 + struct squashfs_xattr_val val; 60 + const struct xattr_handler *handler; 61 + int name_size, prefix_size = 0; 62 + 63 + err = squashfs_read_metadata(sb, &entry, &start, &offset, 64 + sizeof(entry)); 65 + if (err < 0) 66 + goto failed; 67 + 68 + name_size = le16_to_cpu(entry.size); 69 + handler = squashfs_xattr_handler(le16_to_cpu(entry.type)); 70 + if (handler) 71 + prefix_size = handler->list(d, buffer, rest, NULL, 72 + name_size, handler->flags); 73 + if (prefix_size) { 74 + if (buffer) { 75 + if (prefix_size + name_size + 1 > rest) { 76 + err = -ERANGE; 77 + goto failed; 78 + } 79 + buffer += prefix_size; 80 + } 81 + err = squashfs_read_metadata(sb, buffer, &start, 82 + &offset, name_size); 83 + if (err < 0) 84 + goto failed; 85 + if (buffer) { 86 + buffer[name_size] = '\0'; 87 + buffer += name_size + 1; 88 + } 89 + rest -= prefix_size + name_size + 1; 90 + } else { 91 + /* no handler or insuffficient privileges, so skip */ 92 + err = squashfs_read_metadata(sb, NULL, &start, 93 + &offset, name_size); 94 + if (err < 0) 95 + goto failed; 96 + } 97 + 98 + 99 + /* skip remaining xattr entry */ 100 + err = squashfs_read_metadata(sb, &val, &start, &offset, 101 + sizeof(val)); 102 + if (err < 0) 103 + goto failed; 104 + 105 + err = squashfs_read_metadata(sb, NULL, &start, &offset, 106 + le32_to_cpu(val.vsize)); 107 + if (err < 0) 108 + goto failed; 109 + } 110 + err = buffer_size - rest; 111 + 112 + failed: 113 + return err; 114 + } 115 + 116 + 117 + static int squashfs_xattr_get(struct inode *inode, int name_index, 118 + const char *name, void *buffer, size_t buffer_size) 119 + { 120 + struct super_block *sb = inode->i_sb; 121 + struct squashfs_sb_info *msblk = sb->s_fs_info; 122 + u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) 123 + + msblk->xattr_table; 124 + int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); 125 + int count = squashfs_i(inode)->xattr_count; 126 + int name_len = strlen(name); 127 + int err, vsize; 128 + char *target = kmalloc(name_len, GFP_KERNEL); 129 + 130 + if (target == NULL) 131 + return -ENOMEM; 132 + 133 + /* loop reading each xattr name */ 134 + for (; count; count--) { 135 + struct squashfs_xattr_entry entry; 136 + struct squashfs_xattr_val val; 137 + int type, prefix, name_size; 138 + 139 + err = squashfs_read_metadata(sb, &entry, &start, &offset, 140 + sizeof(entry)); 141 + if (err < 0) 142 + goto failed; 143 + 144 + name_size = le16_to_cpu(entry.size); 145 + type = le16_to_cpu(entry.type); 146 + prefix = type & SQUASHFS_XATTR_PREFIX_MASK; 147 + 148 + if (prefix == name_index && name_size == name_len) 149 + err = squashfs_read_metadata(sb, target, &start, 150 + &offset, name_size); 151 + else 152 + err = squashfs_read_metadata(sb, NULL, &start, 153 + &offset, name_size); 154 + if (err < 0) 155 + goto failed; 156 + 157 + if (prefix == name_index && name_size == name_len && 158 + strncmp(target, name, name_size) == 0) { 159 + /* found xattr */ 160 + if (type & SQUASHFS_XATTR_VALUE_OOL) { 161 + __le64 xattr; 162 + /* val is a reference to the real location */ 163 + err = squashfs_read_metadata(sb, &val, &start, 164 + &offset, sizeof(val)); 165 + if (err < 0) 166 + goto failed; 167 + err = squashfs_read_metadata(sb, &xattr, &start, 168 + &offset, sizeof(xattr)); 169 + if (err < 0) 170 + goto failed; 171 + xattr = le64_to_cpu(xattr); 172 + start = SQUASHFS_XATTR_BLK(xattr) + 173 + msblk->xattr_table; 174 + offset = SQUASHFS_XATTR_OFFSET(xattr); 175 + } 176 + /* read xattr value */ 177 + err = squashfs_read_metadata(sb, &val, &start, &offset, 178 + sizeof(val)); 179 + if (err < 0) 180 + goto failed; 181 + 182 + vsize = le32_to_cpu(val.vsize); 183 + if (buffer) { 184 + if (vsize > buffer_size) { 185 + err = -ERANGE; 186 + goto failed; 187 + } 188 + err = squashfs_read_metadata(sb, buffer, &start, 189 + &offset, vsize); 190 + if (err < 0) 191 + goto failed; 192 + } 193 + break; 194 + } 195 + 196 + /* no match, skip remaining xattr entry */ 197 + err = squashfs_read_metadata(sb, &val, &start, &offset, 198 + sizeof(val)); 199 + if (err < 0) 200 + goto failed; 201 + err = squashfs_read_metadata(sb, NULL, &start, &offset, 202 + le32_to_cpu(val.vsize)); 203 + if (err < 0) 204 + goto failed; 205 + } 206 + err = count ? vsize : -ENODATA; 207 + 208 + failed: 209 + kfree(target); 210 + return err; 211 + } 212 + 213 + 214 + /* 215 + * User namespace support 216 + */ 217 + static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size, 218 + const char *name, size_t name_len, int type) 219 + { 220 + if (list && XATTR_USER_PREFIX_LEN <= list_size) 221 + memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); 222 + return XATTR_USER_PREFIX_LEN; 223 + } 224 + 225 + static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, 226 + size_t size, int type) 227 + { 228 + if (name[0] == '\0') 229 + return -EINVAL; 230 + 231 + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name, 232 + buffer, size); 233 + } 234 + 235 + static const struct xattr_handler squashfs_xattr_user_handler = { 236 + .prefix = XATTR_USER_PREFIX, 237 + .list = squashfs_user_list, 238 + .get = squashfs_user_get 239 + }; 240 + 241 + /* 242 + * Trusted namespace support 243 + */ 244 + static size_t squashfs_trusted_list(struct dentry *d, char *list, 245 + size_t list_size, const char *name, size_t name_len, int type) 246 + { 247 + if (!capable(CAP_SYS_ADMIN)) 248 + return 0; 249 + 250 + if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size) 251 + memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); 252 + return XATTR_TRUSTED_PREFIX_LEN; 253 + } 254 + 255 + static int squashfs_trusted_get(struct dentry *d, const char *name, 256 + void *buffer, size_t size, int type) 257 + { 258 + if (name[0] == '\0') 259 + return -EINVAL; 260 + 261 + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name, 262 + buffer, size); 263 + } 264 + 265 + static const struct xattr_handler squashfs_xattr_trusted_handler = { 266 + .prefix = XATTR_TRUSTED_PREFIX, 267 + .list = squashfs_trusted_list, 268 + .get = squashfs_trusted_get 269 + }; 270 + 271 + /* 272 + * Security namespace support 273 + */ 274 + static size_t squashfs_security_list(struct dentry *d, char *list, 275 + size_t list_size, const char *name, size_t name_len, int type) 276 + { 277 + if (list && XATTR_SECURITY_PREFIX_LEN <= list_size) 278 + memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); 279 + return XATTR_SECURITY_PREFIX_LEN; 280 + } 281 + 282 + static int squashfs_security_get(struct dentry *d, const char *name, 283 + void *buffer, size_t size, int type) 284 + { 285 + if (name[0] == '\0') 286 + return -EINVAL; 287 + 288 + return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name, 289 + buffer, size); 290 + } 291 + 292 + static const struct xattr_handler squashfs_xattr_security_handler = { 293 + .prefix = XATTR_SECURITY_PREFIX, 294 + .list = squashfs_security_list, 295 + .get = squashfs_security_get 296 + }; 297 + 298 + static inline const struct xattr_handler *squashfs_xattr_handler(int type) 299 + { 300 + if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) 301 + /* ignore unrecognised type */ 302 + return NULL; 303 + 304 + switch (type & SQUASHFS_XATTR_PREFIX_MASK) { 305 + case SQUASHFS_XATTR_USER: 306 + return &squashfs_xattr_user_handler; 307 + case SQUASHFS_XATTR_TRUSTED: 308 + return &squashfs_xattr_trusted_handler; 309 + case SQUASHFS_XATTR_SECURITY: 310 + return &squashfs_xattr_security_handler; 311 + default: 312 + /* ignore unrecognised type */ 313 + return NULL; 314 + } 315 + } 316 + 317 + const struct xattr_handler *squashfs_xattr_handlers[] = { 318 + &squashfs_xattr_user_handler, 319 + &squashfs_xattr_trusted_handler, 320 + &squashfs_xattr_security_handler, 321 + NULL 322 + }; 323 +
+46
fs/squashfs/xattr.h
···
··· 1 + /* 2 + * Squashfs - a compressed read only filesystem for Linux 3 + * 4 + * Copyright (c) 2010 5 + * Phillip Lougher <phillip@lougher.demon.co.uk> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * as published by the Free Software Foundation; either version 2, 10 + * or (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License 18 + * along with this program; if not, write to the Free Software 19 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 + * 21 + * xattr.h 22 + */ 23 + 24 + #ifdef CONFIG_SQUASHFS_XATTRS 25 + extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, 26 + u64 *, int *); 27 + extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, 28 + int *, unsigned long long *); 29 + #else 30 + static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, 31 + u64 start, u64 *xattr_table_start, int *xattr_ids) 32 + { 33 + ERROR("Xattrs in filesystem, these will be ignored\n"); 34 + return ERR_PTR(-ENOTSUPP); 35 + } 36 + 37 + static inline int squashfs_xattr_lookup(struct super_block *sb, 38 + unsigned int index, int *count, int *size, 39 + unsigned long long *xattr) 40 + { 41 + return 0; 42 + } 43 + #define squashfs_listxattr NULL 44 + #define generic_getxattr NULL 45 + #define squashfs_xattr_handlers NULL 46 + #endif
+100
fs/squashfs/xattr_id.c
···
··· 1 + /* 2 + * Squashfs - a compressed read only filesystem for Linux 3 + * 4 + * Copyright (c) 2010 5 + * Phillip Lougher <phillip@lougher.demon.co.uk> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * as published by the Free Software Foundation; either version 2, 10 + * or (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License 18 + * along with this program; if not, write to the Free Software 19 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 + * 21 + * xattr_id.c 22 + */ 23 + 24 + /* 25 + * This file implements code to map the 32-bit xattr id stored in the inode 26 + * into the on disk location of the xattr data. 27 + */ 28 + 29 + #include <linux/fs.h> 30 + #include <linux/vfs.h> 31 + #include <linux/slab.h> 32 + 33 + #include "squashfs_fs.h" 34 + #include "squashfs_fs_sb.h" 35 + #include "squashfs_fs_i.h" 36 + #include "squashfs.h" 37 + 38 + /* 39 + * Map xattr id using the xattr id look up table 40 + */ 41 + int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, 42 + int *count, unsigned int *size, unsigned long long *xattr) 43 + { 44 + struct squashfs_sb_info *msblk = sb->s_fs_info; 45 + int block = SQUASHFS_XATTR_BLOCK(index); 46 + int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index); 47 + u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]); 48 + struct squashfs_xattr_id id; 49 + int err; 50 + 51 + err = squashfs_read_metadata(sb, &id, &start_block, &offset, 52 + sizeof(id)); 53 + if (err < 0) 54 + return err; 55 + 56 + *xattr = le64_to_cpu(id.xattr); 57 + *size = le32_to_cpu(id.size); 58 + *count = le32_to_cpu(id.count); 59 + return 0; 60 + } 61 + 62 + 63 + /* 64 + * Read uncompressed xattr id lookup table indexes from disk into memory 65 + */ 66 + __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, 67 + u64 *xattr_table_start, int *xattr_ids) 68 + { 69 + unsigned int len; 70 + __le64 *xid_table; 71 + struct squashfs_xattr_id_table id_table; 72 + int err; 73 + 74 + err = squashfs_read_table(sb, &id_table, start, sizeof(id_table)); 75 + if (err < 0) { 76 + ERROR("unable to read xattr id table\n"); 77 + return ERR_PTR(err); 78 + } 79 + *xattr_table_start = le64_to_cpu(id_table.xattr_table_start); 80 + *xattr_ids = le32_to_cpu(id_table.xattr_ids); 81 + len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); 82 + 83 + TRACE("In read_xattr_index_table, length %d\n", len); 84 + 85 + /* Allocate xattr id lookup table indexes */ 86 + xid_table = kmalloc(len, GFP_KERNEL); 87 + if (xid_table == NULL) { 88 + ERROR("Failed to allocate xattr id index table\n"); 89 + return ERR_PTR(-ENOMEM); 90 + } 91 + 92 + err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len); 93 + if (err < 0) { 94 + ERROR("unable to read xattr id index table\n"); 95 + kfree(xid_table); 96 + return ERR_PTR(err); 97 + } 98 + 99 + return xid_table; 100 + }