From f1f73ba8e9b0eb97f90c6256b94afeb035d97562 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 22 Feb 2008 12:38:02 +0100 Subject: [PATCH 01/41] udf: kill udf_set_blocksize This helper has been quite useless since sb_min_blocksize was introduced and is misnamed while we're at it. Just opencode the few lines in the caller instead. Signed-off-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/udf/super.c | 43 ++++--------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index f3ac4abfc946..3723f04c0799 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -587,44 +587,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) return 0; } -/* - * udf_set_blocksize - * - * PURPOSE - * Set the block size to be used in all transfers. - * - * DESCRIPTION - * To allow room for a DMA transfer, it is best to guess big when unsure. - * This routine picks 2048 bytes as the blocksize when guessing. This - * should be adequate until devices with larger block sizes become common. - * - * Note that the Linux kernel can currently only deal with blocksizes of - * 512, 1024, 2048, 4096, and 8192 bytes. - * - * PRE-CONDITIONS - * sb Pointer to _locked_ superblock. - * - * POST-CONDITIONS - * sb->s_blocksize Blocksize. - * sb->s_blocksize_bits log2 of blocksize. - * 0 Blocksize is valid. - * 1 Blocksize is invalid. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ -static int udf_set_blocksize(struct super_block *sb, int bsize) -{ - if (!sb_min_blocksize(sb, bsize)) { - udf_debug("Bad block size (%d)\n", bsize); - printk(KERN_ERR "udf: bad block size (%d)\n", bsize); - return 0; - } - - return sb->s_blocksize; -} - static int udf_vrs(struct super_block *sb, int silent) { struct volStructDesc *vsd = NULL; @@ -1776,8 +1738,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sbi->s_nls_map = uopt.nls_map; /* Set the block size for all transfers */ - if (!udf_set_blocksize(sb, uopt.blocksize)) + if (!sb_min_blocksize(sb, uopt.blocksize)) { + udf_debug("Bad block size (%d)\n", uopt.blocksize); + printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize); goto error_out; + } if (uopt.session == 0xFFFFFFFF) sbi->s_session = udf_get_last_session(sb); From b1e321266d8797b21eac433b11458ac65b098938 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 22 Feb 2008 12:38:48 +0100 Subject: [PATCH 02/41] udf: kill useless file header comments for vfs method implementations There's not need to document vfs method invocation rules, we have Documentation/filesystems/vfs.txt and Documentation/filesystems/Locking for that. Also a lot of these comments where either plain wrong or horrible out of date. Signed-off-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/udf/dir.c | 26 -------------------------- fs/udf/file.c | 46 ---------------------------------------------- fs/udf/inode.c | 32 +------------------------------- fs/udf/namei.c | 33 --------------------------------- fs/udf/super.c | 42 ------------------------------------------ 5 files changed, 1 insertion(+), 178 deletions(-) diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 8d8643ada199..31feef916fb7 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -188,32 +188,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, return 0; } -/* - * udf_readdir - * - * PURPOSE - * Read a directory entry. - * - * DESCRIPTION - * Optional - sys_getdents() will return -ENOTDIR if this routine is not - * available. - * - * Refer to sys_getdents() in fs/readdir.c - * sys_getdents() -> . - * - * PRE-CONDITIONS - * filp Pointer to directory file. - * buf Pointer to directory entry buffer. - * filldir Pointer to filldir function. - * - * POST-CONDITIONS - * >=0 on success. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ - static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *dir = filp->f_path.dentry->d_inode; diff --git a/fs/udf/file.c b/fs/udf/file.c index 97c71ae7c689..822cc4071527 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -144,40 +144,6 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, return retval; } -/* - * udf_ioctl - * - * PURPOSE - * Issue an ioctl. - * - * DESCRIPTION - * Optional - sys_ioctl() will return -ENOTTY if this routine is not - * available, and the ioctl cannot be handled without filesystem help. - * - * sys_ioctl() handles these ioctls that apply only to regular files: - * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD - * These ioctls are also handled by sys_ioctl(): - * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC - * All other ioctls are passed to the filesystem. - * - * Refer to sys_ioctl() in fs/ioctl.c - * sys_ioctl() -> . - * - * PRE-CONDITIONS - * inode Pointer to inode that ioctl was issued on. - * filp Pointer to file that ioctl was issued on. - * cmd The ioctl command. - * arg The ioctl argument [can be interpreted as a - * user-space pointer if desired]. - * - * POST-CONDITIONS - * Success (>=0) or an error code (<=0) that - * sys_ioctl() will return. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -225,18 +191,6 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return result; } -/* - * udf_release_file - * - * PURPOSE - * Called when all references to the file are closed - * - * DESCRIPTION - * Discard prealloced blocks - * - * HISTORY - * - */ static int udf_release_file(struct inode *inode, struct file *filp) { if (filp->f_mode & FMODE_WRITE) { diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 24cfa55d0fdc..dc2f946dfca9 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -66,22 +66,7 @@ static void udf_update_extents(struct inode *, struct extent_position *); static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); -/* - * udf_delete_inode - * - * PURPOSE - * Clean-up before the specified inode is destroyed. - * - * DESCRIPTION - * This routine is called when the kernel destroys an inode structure - * ie. when iput() finds i_count == 0. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - * - * Called at the last iput() if i_nlink is zero. - */ + void udf_delete_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); @@ -1416,21 +1401,6 @@ static mode_t udf_convert_permissions(struct fileEntry *fe) return mode; } -/* - * udf_write_inode - * - * PURPOSE - * Write out the specified inode. - * - * DESCRIPTION - * This routine is called whenever an inode is synced. - * Currently this routine is just a placeholder. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ - int udf_write_inode(struct inode *inode, int sync) { int ret; diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 112a5fb0b27b..ac7f72779e93 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -251,39 +251,6 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, return NULL; } -/* - * udf_lookup - * - * PURPOSE - * Look-up the inode for a given name. - * - * DESCRIPTION - * Required - lookup_dentry() will return -ENOTDIR if this routine is not - * available for a directory. The filesystem is useless if this routine is - * not available for at least the filesystem's root directory. - * - * This routine is passed an incomplete dentry - it must be completed by - * calling d_add(dentry, inode). If the name does not exist, then the - * specified inode must be set to null. An error should only be returned - * when the lookup fails for a reason other than the name not existing. - * Note that the directory inode semaphore is held during the call. - * - * Refer to lookup_dentry() in fs/namei.c - * lookup_dentry() -> lookup() -> real_lookup() -> . - * - * PRE-CONDITIONS - * dir Pointer to inode of parent directory. - * dentry Pointer to dentry to complete. - * nd Pointer to lookup nameidata - * - * POST-CONDITIONS - * Zero on success. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ - static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { diff --git a/fs/udf/super.c b/fs/udf/super.c index 3723f04c0799..53e1d6e6dd31 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1670,22 +1670,6 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) vfree(bitmap); } -/* - * udf_read_super - * - * PURPOSE - * Complete the specified super block. - * - * PRE-CONDITIONS - * sb Pointer to superblock to complete - never NULL. - * sb->s_dev Device to read suberblock from. - * options Pointer to mount options. - * silent Silent flag. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ static int udf_fill_super(struct super_block *sb, void *options, int silent) { int i; @@ -1913,19 +1897,6 @@ void udf_warning(struct super_block *sb, const char *function, sb->s_id, function, error_buf); } -/* - * udf_put_super - * - * PURPOSE - * Prepare for destruction of the superblock. - * - * DESCRIPTION - * Called before the filesystem is unmounted. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ static void udf_put_super(struct super_block *sb) { int i; @@ -1961,19 +1932,6 @@ static void udf_put_super(struct super_block *sb) sb->s_fs_info = NULL; } -/* - * udf_stat_fs - * - * PURPOSE - * Return info about the filesystem. - * - * DESCRIPTION - * Called by sys_statfs() - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; From 15aebd2866b21a568d8defec134bf29f9aea9088 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 22 Feb 2008 12:39:12 +0100 Subject: [PATCH 03/41] udf: move headers out include/linux/ There's really no reason to keep udf headers in include/linux as they're not used by anything but fs/udf/. This patch merges most of include/linux/udf_fs_i.h into fs/udf/udf_i.h, include/linux/udf_fs_sb.h into fs/udf/udf_sb.h and include/linux/udf_fs.h into fs/udf/udfdecl.h. The only thing remaining in include/linux/ is a stub of udf_fs_i.h defining the four user-visible udf ioctls. It's also moved from unifdef-y to headers-y because it can be included unconditionally now. Signed-off-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/udf/file.c | 1 - fs/udf/ialloc.c | 1 - fs/udf/lowlevel.c | 1 - fs/udf/misc.c | 1 - fs/udf/partition.c | 1 - fs/udf/super.c | 1 - fs/udf/symlink.c | 1 - fs/udf/truncate.c | 1 - fs/udf/udf_i.h | 30 ++++++++-- fs/udf/udf_sb.h | 93 ++++++++++++++++++++++++++++++ fs/udf/udfdecl.h | 25 +++++++- fs/udf/unicode.c | 1 - include/linux/Kbuild | 2 +- include/linux/udf_fs.h | 51 ----------------- include/linux/udf_fs_i.h | 31 ---------- include/linux/udf_fs_sb.h | 117 -------------------------------------- 16 files changed, 142 insertions(+), 216 deletions(-) delete mode 100644 include/linux/udf_fs.h delete mode 100644 include/linux/udf_fs_sb.h diff --git a/fs/udf/file.c b/fs/udf/file.c index 822cc4071527..0ed6e146a0d9 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -27,7 +27,6 @@ #include "udfdecl.h" #include -#include #include #include #include /* memset */ diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 84360315aca2..c3fb28eee646 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -21,7 +21,6 @@ #include "udfdecl.h" #include #include -#include #include #include diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 579bae71e67e..703843f30ffd 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c @@ -23,7 +23,6 @@ #include #include -#include #include "udf_sb.h" unsigned int udf_get_last_session(struct super_block *sb) diff --git a/fs/udf/misc.c b/fs/udf/misc.c index a1d6da0caf71..581b6e4cc591 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "udf_i.h" diff --git a/fs/udf/partition.c b/fs/udf/partition.c index fc533345ab89..307c9c33d184 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/fs/udf/super.c b/fs/udf/super.c index 53e1d6e6dd31..02815e92553b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -57,7 +57,6 @@ #include #include -#include #include "udf_sb.h" #include "udf_i.h" diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 6ec99221e50c..c3265e1385d4 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index fe61be17cdab..6111d97902d7 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -22,7 +22,6 @@ #include "udfdecl.h" #include #include -#include #include #include "udf_i.h" diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index ccc52f16bf7d..d6d9a774a1c1 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h @@ -1,10 +1,32 @@ -#ifndef __LINUX_UDF_I_H -#define __LINUX_UDF_I_H +#ifndef _UDF_I_H +#define _UDF_I_H + +struct udf_inode_info { + struct timespec i_crtime; + /* Physical address of inode */ + kernel_lb_addr i_location; + __u64 i_unique; + __u32 i_lenEAttr; + __u32 i_lenAlloc; + __u64 i_lenExtents; + __u32 i_next_alloc_block; + __u32 i_next_alloc_goal; + unsigned i_alloc_type : 3; + unsigned i_efe : 1; + unsigned i_use : 1; + unsigned i_strat4096 : 1; + unsigned reserved : 26; + union { + short_ad *i_sad; + long_ad *i_lad; + __u8 *i_data; + } i_ext; + struct inode vfs_inode; +}; -#include static inline struct udf_inode_info *UDF_I(struct inode *inode) { return list_entry(inode, struct udf_inode_info, vfs_inode); } -#endif /* !defined(_LINUX_UDF_I_H) */ +#endif /* _UDF_I_H) */ diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 737d1c604eea..fb2a6e9f8dac 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -1,6 +1,8 @@ #ifndef __LINUX_UDF_SB_H #define __LINUX_UDF_SB_H +#include + /* Since UDF 2.01 is ISO 13346 based... */ #define UDF_SUPER_MAGIC 0x15013346 @@ -38,6 +40,97 @@ #define UDF_PART_FLAG_REWRITABLE 0x0040 #define UDF_PART_FLAG_OVERWRITABLE 0x0080 +#define UDF_MAX_BLOCK_LOADED 8 + +#define UDF_TYPE1_MAP15 0x1511U +#define UDF_VIRTUAL_MAP15 0x1512U +#define UDF_VIRTUAL_MAP20 0x2012U +#define UDF_SPARABLE_MAP15 0x1522U + +#pragma pack(1) /* XXX(hch): Why? This file just defines in-core structures */ + +struct udf_sparing_data { + __u16 s_packet_len; + struct buffer_head *s_spar_map[4]; +}; + +struct udf_virtual_data { + __u32 s_num_entries; + __u16 s_start_offset; +}; + +struct udf_bitmap { + __u32 s_extLength; + __u32 s_extPosition; + __u16 s_nr_groups; + struct buffer_head **s_block_bitmap; +}; + +struct udf_part_map { + union { + struct udf_bitmap *s_bitmap; + struct inode *s_table; + } s_uspace; + union { + struct udf_bitmap *s_bitmap; + struct inode *s_table; + } s_fspace; + __u32 s_partition_root; + __u32 s_partition_len; + __u16 s_partition_type; + __u16 s_partition_num; + union { + struct udf_sparing_data s_sparing; + struct udf_virtual_data s_virtual; + } s_type_specific; + __u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32); + __u16 s_volumeseqnum; + __u16 s_partition_flags; +}; + +#pragma pack() + +struct udf_sb_info { + struct udf_part_map *s_partmaps; + __u8 s_volume_ident[32]; + + /* Overall info */ + __u16 s_partitions; + __u16 s_partition; + + /* Sector headers */ + __s32 s_session; + __u32 s_anchor[4]; + __u32 s_last_block; + + struct buffer_head *s_lvid_bh; + + /* Default permissions */ + mode_t s_umask; + gid_t s_gid; + uid_t s_uid; + + /* Root Info */ + struct timespec s_record_time; + + /* Fileset Info */ + __u16 s_serial_number; + + /* highest UDF revision we have recorded to this media */ + __u16 s_udfrev; + + /* Miscellaneous flags */ + __u32 s_flags; + + /* Encoding info */ + struct nls_table *s_nls_map; + + /* VAT inode */ + struct inode *s_vat_inode; + + struct mutex s_alloc_mutex; +}; + static inline struct udf_sb_info *UDF_SB(struct super_block *sb) { return sb->s_fs_info; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 681dc2b66cdb..c9c75856af80 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -1,18 +1,37 @@ #ifndef __UDF_DECL_H #define __UDF_DECL_H -#include #include "ecma_167.h" #include "osta_udf.h" #include #include -#include -#include #include +#include +#include "udf_sb.h" #include "udfend.h" +#define UDF_PREALLOCATE +#define UDF_DEFAULT_PREALLOC_BLOCKS 8 + +#undef UDFFS_DEBUG + +#ifdef UDFFS_DEBUG +#define udf_debug(f, a...) \ +do { \ + printk(KERN_DEBUG "UDF-fs DEBUG %s:%d:%s: ", \ + __FILE__, __LINE__, __func__); \ + printk(f, ##a); \ +} while (0) +#else +#define udf_debug(f, a...) /**/ +#endif + +#define udf_info(f, a...) \ + printk(KERN_INFO "UDF-fs INFO " f, ##a); + + #define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) ) #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index e533b11703bf..b9de050ad830 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -23,7 +23,6 @@ #include #include /* for memset */ #include -#include #include "udf_sb.h" diff --git a/include/linux/Kbuild b/include/linux/Kbuild index aada32fffec2..897d84e04985 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -149,6 +149,7 @@ header-y += tiocl.h header-y += tipc.h header-y += tipc_config.h header-y += toshiba.h +header-y += udf_fs_i.h header-y += ultrasound.h header-y += un.h header-y += utime.h @@ -336,7 +337,6 @@ unifdef-y += time.h unifdef-y += timex.h unifdef-y += tty.h unifdef-y += types.h -unifdef-y += udf_fs_i.h unifdef-y += udp.h unifdef-y += uinput.h unifdef-y += uio.h diff --git a/include/linux/udf_fs.h b/include/linux/udf_fs.h deleted file mode 100644 index aa88654eb76b..000000000000 --- a/include/linux/udf_fs.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * udf_fs.h - * - * PURPOSE - * Included by fs/filesystems.c - * - * DESCRIPTION - * OSTA-UDF(tm) = Optical Storage Technology Association - * Universal Disk Format. - * - * This code is based on version 2.50 of the UDF specification, - * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. - * http://www.osta.org/ * http://www.ecma.ch/ - * http://www.iso.org/ - * - * COPYRIGHT - * This file is distributed under the terms of the GNU General Public - * License (GPL). Copies of the GPL can be obtained from: - * ftp://prep.ai.mit.edu/pub/gnu/GPL - * Each contributing author retains all rights to their own work. - * - * (C) 1999-2004 Ben Fennema - * (C) 1999-2000 Stelias Computing Inc - * - * HISTORY - * - */ - -#ifndef _UDF_FS_H -#define _UDF_FS_H 1 - -#define UDF_PREALLOCATE -#define UDF_DEFAULT_PREALLOC_BLOCKS 8 - -#undef UDFFS_DEBUG - -#ifdef UDFFS_DEBUG -#define udf_debug(f, a...) \ - do { \ - printk (KERN_DEBUG "UDF-fs DEBUG %s:%d:%s: ", \ - __FILE__, __LINE__, __FUNCTION__); \ - printk (f, ##a); \ - } while (0) -#else -#define udf_debug(f, a...) /**/ -#endif - -#define udf_info(f, a...) \ - printk (KERN_INFO "UDF-fs INFO " f, ##a); - -#endif /* _UDF_FS_H */ diff --git a/include/linux/udf_fs_i.h b/include/linux/udf_fs_i.h index ffaf05679ffb..3536965913b0 100644 --- a/include/linux/udf_fs_i.h +++ b/include/linux/udf_fs_i.h @@ -9,41 +9,10 @@ * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. */ - #ifndef _UDF_FS_I_H #define _UDF_FS_I_H 1 -#ifdef __KERNEL__ - -struct udf_inode_info -{ - struct timespec i_crtime; - /* Physical address of inode */ - kernel_lb_addr i_location; - __u64 i_unique; - __u32 i_lenEAttr; - __u32 i_lenAlloc; - __u64 i_lenExtents; - __u32 i_next_alloc_block; - __u32 i_next_alloc_goal; - unsigned i_alloc_type : 3; - unsigned i_efe : 1; - unsigned i_use : 1; - unsigned i_strat4096 : 1; - unsigned reserved : 26; - union - { - short_ad *i_sad; - long_ad *i_lad; - __u8 *i_data; - } i_ext; - struct inode vfs_inode; -}; - -#endif - /* exported IOCTLs, we have 'l', 0x40-0x7f */ - #define UDF_GETEASIZE _IOR('l', 0x40, int) #define UDF_GETEABLOCK _IOR('l', 0x41, void *) #define UDF_GETVOLIDENT _IOR('l', 0x42, void *) diff --git a/include/linux/udf_fs_sb.h b/include/linux/udf_fs_sb.h deleted file mode 100644 index 9bc47352b6b4..000000000000 --- a/include/linux/udf_fs_sb.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * udf_fs_sb.h - * - * This include file is for the Linux kernel/module. - * - * COPYRIGHT - * This file is distributed under the terms of the GNU General Public - * License (GPL). Copies of the GPL can be obtained from: - * ftp://prep.ai.mit.edu/pub/gnu/GPL - * Each contributing author retains all rights to their own work. - */ - -#ifndef _UDF_FS_SB_H -#define _UDF_FS_SB_H 1 - -#include - -#pragma pack(1) - -#define UDF_MAX_BLOCK_LOADED 8 - -#define UDF_TYPE1_MAP15 0x1511U -#define UDF_VIRTUAL_MAP15 0x1512U -#define UDF_VIRTUAL_MAP20 0x2012U -#define UDF_SPARABLE_MAP15 0x1522U - -struct udf_sparing_data -{ - __u16 s_packet_len; - struct buffer_head *s_spar_map[4]; -}; - -struct udf_virtual_data -{ - __u32 s_num_entries; - __u16 s_start_offset; -}; - -struct udf_bitmap -{ - __u32 s_extLength; - __u32 s_extPosition; - __u16 s_nr_groups; - struct buffer_head **s_block_bitmap; -}; - -struct udf_part_map -{ - union - { - struct udf_bitmap *s_bitmap; - struct inode *s_table; - } s_uspace; - union - { - struct udf_bitmap *s_bitmap; - struct inode *s_table; - } s_fspace; - __u32 s_partition_root; - __u32 s_partition_len; - __u16 s_partition_type; - __u16 s_partition_num; - union - { - struct udf_sparing_data s_sparing; - struct udf_virtual_data s_virtual; - } s_type_specific; - __u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32); - __u16 s_volumeseqnum; - __u16 s_partition_flags; -}; - -#pragma pack() - -struct udf_sb_info -{ - struct udf_part_map *s_partmaps; - __u8 s_volume_ident[32]; - - /* Overall info */ - __u16 s_partitions; - __u16 s_partition; - - /* Sector headers */ - __s32 s_session; - __u32 s_anchor[4]; - __u32 s_last_block; - - struct buffer_head *s_lvid_bh; - - /* Default permissions */ - mode_t s_umask; - gid_t s_gid; - uid_t s_uid; - - /* Root Info */ - struct timespec s_record_time; - - /* Fileset Info */ - __u16 s_serial_number; - - /* highest UDF revision we have recorded to this media */ - __u16 s_udfrev; - - /* Miscellaneous flags */ - __u32 s_flags; - - /* Encoding info */ - struct nls_table *s_nls_map; - - /* VAT inode */ - struct inode *s_vat_inode; - - struct mutex s_alloc_mutex; -}; - -#endif /* _UDF_FS_SB_H */ From 8dee00bb758f9e1d7fac9f5d2463d09444d4f255 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 14 Feb 2008 16:15:45 +0100 Subject: [PATCH 04/41] fs/udf: Use DIV_ROUND_UP The kernel.h macro DIV_ROUND_UP performs the computation (((n) + (d) - 1) / (d)) but is perhaps more readable. An extract of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression n,d; @@ ( - (n + d - 1) / d + DIV_ROUND_UP(n,d) | - (n + (d - 1)) / d + DIV_ROUND_UP(n,d) ) @depends on haskernel@ expression n,d; @@ - DIV_ROUND_UP((n),d) + DIV_ROUND_UP(n,d) @depends on haskernel@ expression n,d; @@ - DIV_ROUND_UP(n,(d)) + DIV_ROUND_UP(n,d) // Signed-off-by: Julia Lawall Signed-off-by: Jan Kara --- fs/udf/super.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 02815e92553b..5f0d400385e0 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -986,10 +986,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, int udf_compute_nr_groups(struct super_block *sb, u32 partition) { struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; - return (map->s_partition_len + - (sizeof(struct spaceBitmapDesc) << 3) + - (sb->s_blocksize * 8) - 1) / - (sb->s_blocksize * 8); + return DIV_ROUND_UP(map->s_partition_len + + (sizeof(struct spaceBitmapDesc) << 3), + sb->s_blocksize * 8); } static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) From b8145a769765ce9688eb84080d4c48b22a3553f2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 17 Feb 2008 10:19:55 +0200 Subject: [PATCH 05/41] make udf_error() static This patch makes the needlessly global udf_error() static. Signed-off-by: Adrian Bunk Signed-off-by: Jan Kara --- fs/udf/super.c | 6 ++++-- fs/udf/udfdecl.h | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 5f0d400385e0..2666e5bc69ff 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -99,6 +99,8 @@ static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); static int udf_statfs(struct dentry *, struct kstatfs *); static int udf_show_options(struct seq_file *, struct vfsmount *); +static void udf_error(struct super_block *sb, const char *function, + const char *fmt, ...); struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) { @@ -1867,8 +1869,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) return -EINVAL; } -void udf_error(struct super_block *sb, const char *function, - const char *fmt, ...) +static void udf_error(struct super_block *sb, const char *function, + const char *fmt, ...) { va_list args; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index c9c75856af80..d3aae5633722 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -102,7 +102,6 @@ struct extent_position { }; /* super.c */ -extern void udf_error(struct super_block *, const char *, const char *, ...); extern void udf_warning(struct super_block *, const char *, const char *, ...); /* namei.c */ From 79cfe0ff5fb585b92126365a2881262945ac0ee9 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 30 Jan 2008 22:03:51 +0100 Subject: [PATCH 06/41] udf: udf_CS0toUTF8 cleanup - fix error handling - always zero output variable - don't zero explicitely fields zeroed by memset - mark "in" paramater as const - remove outdated comment Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/udfdecl.h | 2 +- fs/udf/unicode.c | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index d3aae5633722..2310b5c8fd8b 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -175,7 +175,7 @@ extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int); extern int udf_build_ustr(struct ustr *, dstring *, int); -extern int udf_CS0toUTF8(struct ustr *, struct ustr *); +extern int udf_CS0toUTF8(struct ustr *, const struct ustr *); /* ialloc.c */ extern void udf_free_inode(struct inode *); diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index b9de050ad830..05bc505ec01a 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -82,9 +82,6 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) * PURPOSE * Convert OSTA Compressed Unicode to the UTF-8 equivalent. * - * DESCRIPTION - * This routine is only called by udf_filldir(). - * * PRE-CONDITIONS * utf Pointer to UTF-8 output buffer. * ocu Pointer to OSTA Compressed Unicode input buffer @@ -98,43 +95,39 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) * November 12, 1997 - Andrew E. Mileski * Written, tested, and released. */ -int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) +int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) { - uint8_t *ocu; - uint32_t c; + const uint8_t *ocu; uint8_t cmp_id, ocu_len; int i; - ocu = ocu_i->u_name; - ocu_len = ocu_i->u_len; - cmp_id = ocu_i->u_cmpID; - utf_o->u_len = 0; - if (ocu_len == 0) { memset(utf_o, 0, sizeof(struct ustr)); - utf_o->u_cmpID = 0; - utf_o->u_len = 0; return 0; } - if ((cmp_id != 8) && (cmp_id != 16)) { + cmp_id = ocu_i->u_cmpID; + if (cmp_id != 8 && cmp_id != 16) { + memset(utf_o, 0, sizeof(struct ustr)); printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); return 0; } + ocu = ocu_i->u_name; + utf_o->u_len = 0; for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { /* Expand OSTA compressed Unicode to Unicode */ - c = ocu[i++]; + uint32_t c = ocu[i++]; if (cmp_id == 16) c = (c << 8) | ocu[i++]; /* Compress Unicode to UTF-8 */ - if (c < 0x80U) { + if (c < 0x80U) utf_o->u_name[utf_o->u_len++] = (uint8_t)c; - } else if (c < 0x800U) { + else if (c < 0x800U) { utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6)); utf_o->u_name[utf_o->u_len++] = From 6305a0a9d559e97807b8bc6d5250fd525dc571a7 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Mon, 4 Feb 2008 22:27:39 +0100 Subject: [PATCH 07/41] udf: fix udf_build_ustr udf_build_ustr was broken: - size == 1: dest->u_len = ptr[1 - 1], but at ptr[0] there's cmpID, so we created string with wrong length it should not happen, so we BUG() it - size > 1 and size < UDF_NAME_LEN: we set u_len correctly, but memcpy copied one needless byte - size == UDF_NAME_LEN - 1: memcpy overwrited u_len - with correct value, but... - size >= UDF_NAME_LEN: we copied UDF_NAME_LEN - 1 bytes, but dest->u_name is array of UDF_NAME_LEN - 2 bytes, so we were overwriting u_len with character from input string nobody noticed because all callers set size to acceptable values (constants within range) Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/unicode.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index 05bc505ec01a..24d6165d21a9 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -48,14 +48,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) { int usesize; - if ((!dest) || (!ptr) || (!size)) + if (!dest || !ptr || !size) return -1; + BUG_ON(size < 2); - memset(dest, 0, sizeof(struct ustr)); - usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; + usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name)); + usesize = min(usesize, size - 2); dest->u_cmpID = ptr[0]; - dest->u_len = ptr[size - 1]; - memcpy(dest->u_name, ptr + 1, usesize - 1); + dest->u_len = usesize; + memcpy(dest->u_name, ptr + 1, usesize); + memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize); return 0; } From 34f953ddfd15da8feb5b8383c93c35dc57202b66 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 27 Feb 2008 22:38:36 +0100 Subject: [PATCH 08/41] udf: udf_CS0toNLS cleanup - fix error handling - always zero output variable - don't zero explicitely fields zeroed by memset - mark "in" paramater as const Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/unicode.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index 24d6165d21a9..f5872ae325a3 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -249,35 +249,32 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) } static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, - struct ustr *ocu_i) + const struct ustr *ocu_i) { - uint8_t *ocu; - uint32_t c; + const uint8_t *ocu; uint8_t cmp_id, ocu_len; int i; - ocu = ocu_i->u_name; ocu_len = ocu_i->u_len; - cmp_id = ocu_i->u_cmpID; - utf_o->u_len = 0; - if (ocu_len == 0) { memset(utf_o, 0, sizeof(struct ustr)); - utf_o->u_cmpID = 0; - utf_o->u_len = 0; return 0; } - if ((cmp_id != 8) && (cmp_id != 16)) { + cmp_id = ocu_i->u_cmpID; + if (cmp_id != 8 && cmp_id != 16) { + memset(utf_o, 0, sizeof(struct ustr)); printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); return 0; } + ocu = ocu_i->u_name; + utf_o->u_len = 0; for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { /* Expand OSTA compressed Unicode to Unicode */ - c = ocu[i++]; + uint32_t c = ocu[i++]; if (cmp_id == 16) c = (c << 8) | ocu[i++]; From c8ed837d371c24b678182a30e9f0b1f61dee212c Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 27 Feb 2008 22:38:38 +0100 Subject: [PATCH 09/41] udf: constify crc - constify internal crc table - mark udf_crc "in" parameter as const Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/crc.c | 4 ++-- fs/udf/udfdecl.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/udf/crc.c b/fs/udf/crc.c index b1661296e786..f178c63686e0 100644 --- a/fs/udf/crc.c +++ b/fs/udf/crc.c @@ -23,7 +23,7 @@ #include "udfdecl.h" -static uint16_t crc_table[256] = { +static const uint16_t crc_table[256] = { 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, @@ -79,7 +79,7 @@ static uint16_t crc_table[256] = { * July 21, 1997 - Andrew E. Mileski * Adapted from OSTA-UDF(tm) 1.50 standard. */ -uint16_t udf_crc(uint8_t *data, uint32_t size, uint16_t crc) +uint16_t udf_crc(const uint8_t *data, uint32_t size, uint16_t crc) { while (size--) crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 2310b5c8fd8b..26bc9c237cb7 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -210,7 +210,7 @@ extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); /* crc.c */ -extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t); +extern uint16_t udf_crc(const uint8_t *, uint32_t, uint16_t); /* udftime.c */ extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp); From 9de90b76eb96e7cdeac8b8dbe7d3db948b070f4d Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 30 Jan 2008 22:03:55 +0100 Subject: [PATCH 10/41] udf: simple cleanup of truncate.c - remove one indentation level by little code reorganization - convert "if (smth) BUG();" to "BUG_ON(smth);" Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/truncate.c | 76 +++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index 6111d97902d7..cde328f16775 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -223,34 +223,29 @@ void udf_truncate_extents(struct inode *inode) if (indirect_ext_len) { /* We managed to free all extents in the * indirect extent - free it too */ - if (!epos.bh) - BUG(); + BUG_ON(!epos.bh); udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len); + } else if (!epos.bh) { + iinfo->i_lenAlloc = lenalloc; + mark_inode_dirty(inode); } else { - if (!epos.bh) { - iinfo->i_lenAlloc = - lenalloc; - mark_inode_dirty(inode); - } else { - struct allocExtDesc *aed = - (struct allocExtDesc *) - (epos.bh->b_data); - int len = - sizeof(struct allocExtDesc); + struct allocExtDesc *aed = + (struct allocExtDesc *) + (epos.bh->b_data); + int len = sizeof(struct allocExtDesc); - aed->lengthAllocDescs = - cpu_to_le32(lenalloc); - if (!UDF_QUERY_FLAG(sb, - UDF_FLAG_STRICT) || - sbi->s_udfrev >= 0x0201) - len += lenalloc; + aed->lengthAllocDescs = + cpu_to_le32(lenalloc); + if (!UDF_QUERY_FLAG(sb, + UDF_FLAG_STRICT) || + sbi->s_udfrev >= 0x0201) + len += lenalloc; - udf_update_tag(epos.bh->b_data, - len); - mark_buffer_dirty_inode( - epos.bh, inode); - } + udf_update_tag(epos.bh->b_data, + len); + mark_buffer_dirty_inode( + epos.bh, inode); } brelse(epos.bh); epos.offset = sizeof(struct allocExtDesc); @@ -271,28 +266,25 @@ void udf_truncate_extents(struct inode *inode) } if (indirect_ext_len) { - if (!epos.bh) - BUG(); + BUG_ON(!epos.bh); udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len); + } else if (!epos.bh) { + iinfo->i_lenAlloc = lenalloc; + mark_inode_dirty(inode); } else { - if (!epos.bh) { - iinfo->i_lenAlloc = lenalloc; - mark_inode_dirty(inode); - } else { - struct allocExtDesc *aed = - (struct allocExtDesc *)(epos.bh->b_data); - aed->lengthAllocDescs = cpu_to_le32(lenalloc); - if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || - sbi->s_udfrev >= 0x0201) - udf_update_tag(epos.bh->b_data, - lenalloc + - sizeof(struct allocExtDesc)); - else - udf_update_tag(epos.bh->b_data, - sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(epos.bh, inode); - } + struct allocExtDesc *aed = + (struct allocExtDesc *)(epos.bh->b_data); + aed->lengthAllocDescs = cpu_to_le32(lenalloc); + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || + sbi->s_udfrev >= 0x0201) + udf_update_tag(epos.bh->b_data, + lenalloc + + sizeof(struct allocExtDesc)); + else + udf_update_tag(epos.bh->b_data, + sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(epos.bh, inode); } } else if (inode->i_size) { if (byte_offset) { From 456390de465e5a19c84bca5d78e2550971ab5a96 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 30 Jan 2008 22:03:56 +0100 Subject: [PATCH 11/41] udf: truncate: create function for updating of Allocation Ext Descriptor Signed-off-by: Marcin Slusarz Cc: Jan Kara Signed-off-by: Jan Kara --- fs/udf/truncate.c | 56 +++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index cde328f16775..65e19b4f9424 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -179,6 +179,24 @@ void udf_discard_prealloc(struct inode *inode) brelse(epos.bh); } +static void udf_update_alloc_ext_desc(struct inode *inode, + struct extent_position *epos, + u32 lenalloc) +{ + struct super_block *sb = inode->i_sb; + struct udf_sb_info *sbi = UDF_SB(sb); + + struct allocExtDesc *aed = (struct allocExtDesc *) (epos->bh->b_data); + int len = sizeof(struct allocExtDesc); + + aed->lengthAllocDescs = cpu_to_le32(lenalloc); + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || sbi->s_udfrev >= 0x0201) + len += lenalloc; + + udf_update_tag(epos->bh->b_data, len); + mark_buffer_dirty_inode(epos->bh, inode); +} + void udf_truncate_extents(struct inode *inode) { struct extent_position epos; @@ -186,7 +204,6 @@ void udf_truncate_extents(struct inode *inode) uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; int8_t etype; struct super_block *sb = inode->i_sb; - struct udf_sb_info *sbi = UDF_SB(sb); sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset; loff_t byte_offset; int adsize; @@ -229,24 +246,9 @@ void udf_truncate_extents(struct inode *inode) } else if (!epos.bh) { iinfo->i_lenAlloc = lenalloc; mark_inode_dirty(inode); - } else { - struct allocExtDesc *aed = - (struct allocExtDesc *) - (epos.bh->b_data); - int len = sizeof(struct allocExtDesc); - - aed->lengthAllocDescs = - cpu_to_le32(lenalloc); - if (!UDF_QUERY_FLAG(sb, - UDF_FLAG_STRICT) || - sbi->s_udfrev >= 0x0201) - len += lenalloc; - - udf_update_tag(epos.bh->b_data, - len); - mark_buffer_dirty_inode( - epos.bh, inode); - } + } else + udf_update_alloc_ext_desc(inode, + &epos, lenalloc); brelse(epos.bh); epos.offset = sizeof(struct allocExtDesc); epos.block = eloc; @@ -272,20 +274,8 @@ void udf_truncate_extents(struct inode *inode) } else if (!epos.bh) { iinfo->i_lenAlloc = lenalloc; mark_inode_dirty(inode); - } else { - struct allocExtDesc *aed = - (struct allocExtDesc *)(epos.bh->b_data); - aed->lengthAllocDescs = cpu_to_le32(lenalloc); - if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || - sbi->s_udfrev >= 0x0201) - udf_update_tag(epos.bh->b_data, - lenalloc + - sizeof(struct allocExtDesc)); - else - udf_update_tag(epos.bh->b_data, - sizeof(struct allocExtDesc)); - mark_buffer_dirty_inode(epos.bh, inode); - } + } else + udf_update_alloc_ext_desc(inode, &epos, lenalloc); } else if (inode->i_size) { if (byte_offset) { kernel_long_ad extent; From c2104fda5e6a6981e385b2d11c5c591ab06d82a2 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 30 Jan 2008 22:03:57 +0100 Subject: [PATCH 12/41] udf: replace all adds to little endians variables with le*_add_cpu replace all: little_endian_variable = cpu_to_leX(leX_to_cpu(little_endian_variable) + expression_in_cpu_byteorder); with: leX_add_cpu(&little_endian_variable, expression_in_cpu_byteorder); sparse didn't generate any new warning with this patch Signed-off-by: Marcin Slusarz --- fs/udf/balloc.c | 13 ++++--------- fs/udf/ialloc.c | 12 ++++-------- fs/udf/inode.c | 16 ++++------------ 3 files changed, 12 insertions(+), 29 deletions(-) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index f855dcbbdfb8..1b809bd494bd 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -149,8 +149,7 @@ static bool udf_add_free_space(struct udf_sb_info *sbi, return false; lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; - lvid->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu( - lvid->freeSpaceTable[partition]) + cnt); + le32_add_cpu(&lvid->freeSpaceTable[partition], cnt); return true; } @@ -589,10 +588,8 @@ static void udf_table_free_blocks(struct super_block *sb, sptr = oepos.bh->b_data + epos.offset; aed = (struct allocExtDesc *) oepos.bh->b_data; - aed->lengthAllocDescs = - cpu_to_le32(le32_to_cpu( - aed->lengthAllocDescs) + - adsize); + le32_add_cpu(&aed->lengthAllocDescs, + adsize); } else { sptr = iinfo->i_ext.i_data + epos.offset; @@ -645,9 +642,7 @@ static void udf_table_free_blocks(struct super_block *sb, mark_inode_dirty(table); } else { aed = (struct allocExtDesc *)epos.bh->b_data; - aed->lengthAllocDescs = - cpu_to_le32(le32_to_cpu( - aed->lengthAllocDescs) + adsize); + le32_add_cpu(&aed->lengthAllocDescs, adsize); udf_update_tag(epos.bh->b_data, epos.offset); mark_buffer_dirty(epos.bh); } diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index c3fb28eee646..eb9cfa23dc3d 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -46,11 +46,9 @@ void udf_free_inode(struct inode *inode) struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sbi); if (S_ISDIR(inode->i_mode)) - lvidiu->numDirs = - cpu_to_le32(le32_to_cpu(lvidiu->numDirs) - 1); + le32_add_cpu(&lvidiu->numDirs, -1); else - lvidiu->numFiles = - cpu_to_le32(le32_to_cpu(lvidiu->numFiles) - 1); + le32_add_cpu(&lvidiu->numFiles, -1); mark_buffer_dirty(sbi->s_lvid_bh); } @@ -104,11 +102,9 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) lvhd = (struct logicalVolHeaderDesc *) (lvid->logicalVolContentsUse); if (S_ISDIR(mode)) - lvidiu->numDirs = - cpu_to_le32(le32_to_cpu(lvidiu->numDirs) + 1); + le32_add_cpu(&lvidiu->numDirs, 1); else - lvidiu->numFiles = - cpu_to_le32(le32_to_cpu(lvidiu->numFiles) + 1); + le32_add_cpu(&lvidiu->numFiles, 1); iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID); if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index dc2f946dfca9..91d1f1d3d7a5 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1748,9 +1748,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, if (epos->bh) { aed = (struct allocExtDesc *)epos->bh->b_data; - aed->lengthAllocDescs = - cpu_to_le32(le32_to_cpu( - aed->lengthAllocDescs) + adsize); + le32_add_cpu(&aed->lengthAllocDescs, adsize); } else { iinfo->i_lenAlloc += adsize; mark_inode_dirty(inode); @@ -1800,9 +1798,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)epos->bh->b_data; - aed->lengthAllocDescs = - cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + - adsize); + le32_add_cpu(&aed->lengthAllocDescs, adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) udf_update_tag(epos->bh->b_data, @@ -2016,9 +2012,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)oepos.bh->b_data; - aed->lengthAllocDescs = - cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - - (2 * adsize)); + le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize)); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) udf_update_tag(oepos.bh->b_data, @@ -2035,9 +2029,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)oepos.bh->b_data; - aed->lengthAllocDescs = - cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - - adsize); + le32_add_cpu(&aed->lengthAllocDescs, -adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) udf_update_tag(oepos.bh->b_data, From 1ab9278570077101d1e367399686be62b22c4019 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 30 Jan 2008 22:03:58 +0100 Subject: [PATCH 13/41] udf: simplify __udf_read_inode - move all brelse(ibh) after main if, because it's called on every path except one where ibh is null - move variables to the most inner blocks Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/inode.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 91d1f1d3d7a5..ddd7780d1ab1 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1101,42 +1101,36 @@ static void __udf_read_inode(struct inode *inode) fe = (struct fileEntry *)bh->b_data; if (fe->icbTag.strategyType == cpu_to_le16(4096)) { - struct buffer_head *ibh = NULL, *nbh = NULL; - struct indirectEntry *ie; + struct buffer_head *ibh; ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1, &ident); - if (ident == TAG_IDENT_IE) { - if (ibh) { - kernel_lb_addr loc; - ie = (struct indirectEntry *)ibh->b_data; + if (ident == TAG_IDENT_IE && ibh) { + struct buffer_head *nbh = NULL; + kernel_lb_addr loc; + struct indirectEntry *ie; - loc = lelb_to_cpu(ie->indirectICB.extLocation); + ie = (struct indirectEntry *)ibh->b_data; + loc = lelb_to_cpu(ie->indirectICB.extLocation); - if (ie->indirectICB.extLength && - (nbh = udf_read_ptagged(inode->i_sb, loc, 0, - &ident))) { - if (ident == TAG_IDENT_FE || - ident == TAG_IDENT_EFE) { - memcpy(&iinfo->i_location, - &loc, - sizeof(kernel_lb_addr)); - brelse(bh); - brelse(ibh); - brelse(nbh); - __udf_read_inode(inode); - return; - } else { - brelse(nbh); - brelse(ibh); - } - } else { + if (ie->indirectICB.extLength && + (nbh = udf_read_ptagged(inode->i_sb, loc, 0, + &ident))) { + if (ident == TAG_IDENT_FE || + ident == TAG_IDENT_EFE) { + memcpy(&iinfo->i_location, + &loc, + sizeof(kernel_lb_addr)); + brelse(bh); brelse(ibh); + brelse(nbh); + __udf_read_inode(inode); + return; } + brelse(nbh); } - } else { - brelse(ibh); } + brelse(ibh); } else if (fe->icbTag.strategyType != cpu_to_le16(4)) { printk(KERN_ERR "udf: unsupported strategy type: %d\n", le16_to_cpu(fe->icbTag.strategyType)); From d652eefb70142c64495f4188883f9dfc0430a96b Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 30 Jan 2008 22:03:59 +0100 Subject: [PATCH 14/41] udf: replace udf_*_offset macros with functions - translate udf_file_entry_alloc_offset macro into function - translate udf_ext0_offset macro into function - add comment about crypticly named fields in struct udf_inode_info Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/udf_i.h | 4 ++-- fs/udf/udfdecl.h | 27 ++++++++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index d6d9a774a1c1..4f86b1d98a5d 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h @@ -12,8 +12,8 @@ struct udf_inode_info { __u32 i_next_alloc_block; __u32 i_next_alloc_goal; unsigned i_alloc_type : 3; - unsigned i_efe : 1; - unsigned i_use : 1; + unsigned i_efe : 1; /* extendedFileEntry */ + unsigned i_use : 1; /* unallocSpaceEntry */ unsigned i_strat4096 : 1; unsigned reserved : 26; union { diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 26bc9c237cb7..cc15f58d497a 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -11,6 +11,7 @@ #include "udf_sb.h" #include "udfend.h" +#include "udf_i.h" #define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 @@ -42,16 +43,24 @@ do { \ #define UDF_NAME_LEN 256 #define UDF_PATH_LEN 1023 -#define udf_file_entry_alloc_offset(inode)\ - (UDF_I(inode)->i_use ?\ - sizeof(struct unallocSpaceEntry) :\ - ((UDF_I(inode)->i_efe ?\ - sizeof(struct extendedFileEntry) :\ - sizeof(struct fileEntry)) + UDF_I(inode)->i_lenEAttr)) +static inline size_t udf_file_entry_alloc_offset(struct inode *inode) +{ + struct udf_inode_info *iinfo = UDF_I(inode); + if (iinfo->i_use) + return sizeof(struct unallocSpaceEntry); + else if (iinfo->i_efe) + return sizeof(struct extendedFileEntry) + iinfo->i_lenEAttr; + else + return sizeof(struct fileEntry) + iinfo->i_lenEAttr; +} -#define udf_ext0_offset(inode)\ - (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ?\ - udf_file_entry_alloc_offset(inode) : 0) +static inline size_t udf_ext0_offset(struct inode *inode) +{ + if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) + return udf_file_entry_alloc_offset(inode); + else + return 0; +} #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset)) From 01b954a36a03d90a66c9dd1fc13e4cb51269caf7 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sat, 2 Feb 2008 22:37:07 +0100 Subject: [PATCH 15/41] udf: convert udf_count_free_bitmap to use bitmap_weight replace handwritten bits counting with bitmap_weight Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/super.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 2666e5bc69ff..be0aa424b8f1 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include "udf_sb.h" @@ -1958,10 +1959,6 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static unsigned char udf_bitmap_lookup[16] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 -}; - static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap) { @@ -1971,7 +1968,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, int block = 0, newblock; kernel_lb_addr loc; uint32_t bytes; - uint8_t value; uint8_t *ptr; uint16_t ident; struct spaceBitmapDesc *bm; @@ -1997,13 +1993,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ptr = (uint8_t *)bh->b_data; while (bytes > 0) { - while ((bytes > 0) && (index < sb->s_blocksize)) { - value = ptr[index]; - accum += udf_bitmap_lookup[value & 0x0f]; - accum += udf_bitmap_lookup[value >> 4]; - index++; - bytes--; - } + u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index); + accum += bitmap_weight((const unsigned long *)(ptr + index), + cur_bytes * 8); + bytes -= cur_bytes; if (bytes) { brelse(bh); newblock = udf_get_lb_pblock(sb, loc, ++block); From f18f17b0338a388ad87a2f8078dbbfb83798bdfd Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Sun, 3 Feb 2008 19:36:06 +0100 Subject: [PATCH 16/41] udf: udf_get_block, inode_bmap - remove unneeded checks block cannot be less than 0, because it's sector_t, so remove unneeded checks Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/inode.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index ddd7780d1ab1..fb92476fcdd9 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -308,9 +308,6 @@ static int udf_get_block(struct inode *inode, sector_t block, lock_kernel(); - if (block < 0) - goto abort_negative; - iinfo = UDF_I(inode); if (block == iinfo->i_next_alloc_block + 1) { iinfo->i_next_alloc_block++; @@ -332,10 +329,6 @@ static int udf_get_block(struct inode *inode, sector_t block, abort: unlock_kernel(); return err; - -abort_negative: - udf_warning(inode->i_sb, "udf_get_block", "block < 0"); - goto abort; } static struct buffer_head *udf_getblk(struct inode *inode, long block, @@ -2051,11 +2044,6 @@ int8_t inode_bmap(struct inode *inode, sector_t block, int8_t etype; struct udf_inode_info *iinfo; - if (block < 0) { - printk(KERN_ERR "udf: inode_bmap: block < 0\n"); - return -1; - } - iinfo = UDF_I(inode); pos->offset = 0; pos->block = iinfo->i_location; From c87e8e90d0da1134e42c89dc89559f4bfe282ef9 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Sun, 3 Feb 2008 19:36:07 +0100 Subject: [PATCH 17/41] udf: create function for conversion from timestamp to timespec Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/inode.c | 79 +++++++++++++++----------------------------------- 1 file changed, 23 insertions(+), 56 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index fb92476fcdd9..3c0a60dad478 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1136,12 +1136,24 @@ static void __udf_read_inode(struct inode *inode) brelse(bh); } +static void udf_fill_inode_time(struct timespec *tspec, + const timestamp *tstamp, + struct udf_sb_info *sbi) +{ + time_t convtime; + long convtime_usec; + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(*tstamp))) { + tspec->tv_sec = convtime; + tspec->tv_nsec = convtime_usec * 1000; + } else + *tspec = sbi->s_record_time; +} + static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) { struct fileEntry *fe; struct extendedFileEntry *efe; - time_t convtime; - long convtime_usec; int offset; struct udf_sb_info *sbi = UDF_SB(inode->i_sb); struct udf_inode_info *iinfo = UDF_I(inode); @@ -1229,29 +1241,10 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(fe->accessTime))) { - inode->i_atime.tv_sec = convtime; - inode->i_atime.tv_nsec = convtime_usec * 1000; - } else { - inode->i_atime = sbi->s_record_time; - } - - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(fe->modificationTime))) { - inode->i_mtime.tv_sec = convtime; - inode->i_mtime.tv_nsec = convtime_usec * 1000; - } else { - inode->i_mtime = sbi->s_record_time; - } - - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(fe->attrTime))) { - inode->i_ctime.tv_sec = convtime; - inode->i_ctime.tv_nsec = convtime_usec * 1000; - } else { - inode->i_ctime = sbi->s_record_time; - } + udf_fill_inode_time(&inode->i_atime, &fe->accessTime, sbi); + udf_fill_inode_time(&inode->i_mtime, &fe->modificationTime, + sbi); + udf_fill_inode_time(&inode->i_ctime, &fe->attrTime, sbi); iinfo->i_unique = le64_to_cpu(fe->uniqueID); iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); @@ -1261,37 +1254,11 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(efe->accessTime))) { - inode->i_atime.tv_sec = convtime; - inode->i_atime.tv_nsec = convtime_usec * 1000; - } else { - inode->i_atime = sbi->s_record_time; - } - - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(efe->modificationTime))) { - inode->i_mtime.tv_sec = convtime; - inode->i_mtime.tv_nsec = convtime_usec * 1000; - } else { - inode->i_mtime = sbi->s_record_time; - } - - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(efe->createTime))) { - iinfo->i_crtime.tv_sec = convtime; - iinfo->i_crtime.tv_nsec = convtime_usec * 1000; - } else { - iinfo->i_crtime = sbi->s_record_time; - } - - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(efe->attrTime))) { - inode->i_ctime.tv_sec = convtime; - inode->i_ctime.tv_nsec = convtime_usec * 1000; - } else { - inode->i_ctime = sbi->s_record_time; - } + udf_fill_inode_time(&inode->i_atime, &efe->accessTime, sbi); + udf_fill_inode_time(&inode->i_mtime, &efe->modificationTime, + sbi); + udf_fill_inode_time(&iinfo->i_crtime, &efe->createTime, sbi); + udf_fill_inode_time(&inode->i_ctime, &efe->attrTime, sbi); iinfo->i_unique = le64_to_cpu(efe->uniqueID); iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); From cbf5676a0e0463f05e5073589f3194846dfb02e7 Mon Sep 17 00:00:00 2001 From: "marcin.slusarz@gmail.com" Date: Wed, 27 Feb 2008 22:50:14 +0100 Subject: [PATCH 18/41] udf: convert udf_stamp_to_time to return struct timespec Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/inode.c | 49 +++++++++++++++++++++++++----------------------- fs/udf/super.c | 9 ++------- fs/udf/udfdecl.h | 4 ++-- fs/udf/udftime.c | 17 +++++++---------- 4 files changed, 37 insertions(+), 42 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 3c0a60dad478..a7646e9bdbde 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1136,20 +1136,6 @@ static void __udf_read_inode(struct inode *inode) brelse(bh); } -static void udf_fill_inode_time(struct timespec *tspec, - const timestamp *tstamp, - struct udf_sb_info *sbi) -{ - time_t convtime; - long convtime_usec; - if (udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(*tstamp))) { - tspec->tv_sec = convtime; - tspec->tv_nsec = convtime_usec * 1000; - } else - *tspec = sbi->s_record_time; -} - static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) { struct fileEntry *fe; @@ -1241,10 +1227,17 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - udf_fill_inode_time(&inode->i_atime, &fe->accessTime, sbi); - udf_fill_inode_time(&inode->i_mtime, &fe->modificationTime, - sbi); - udf_fill_inode_time(&inode->i_ctime, &fe->attrTime, sbi); + if (!udf_stamp_to_time(&inode->i_atime, + lets_to_cpu(fe->accessTime))) + inode->i_atime = sbi->s_record_time; + + if (!udf_stamp_to_time(&inode->i_mtime, + lets_to_cpu(fe->modificationTime))) + inode->i_mtime = sbi->s_record_time; + + if (!udf_stamp_to_time(&inode->i_ctime, + lets_to_cpu(fe->attrTime))) + inode->i_ctime = sbi->s_record_time; iinfo->i_unique = le64_to_cpu(fe->uniqueID); iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); @@ -1254,11 +1247,21 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - udf_fill_inode_time(&inode->i_atime, &efe->accessTime, sbi); - udf_fill_inode_time(&inode->i_mtime, &efe->modificationTime, - sbi); - udf_fill_inode_time(&iinfo->i_crtime, &efe->createTime, sbi); - udf_fill_inode_time(&inode->i_ctime, &efe->attrTime, sbi); + if (!udf_stamp_to_time(&inode->i_atime, + lets_to_cpu(efe->accessTime))) + inode->i_atime = sbi->s_record_time; + + if (!udf_stamp_to_time(&inode->i_mtime, + lets_to_cpu(efe->modificationTime))) + inode->i_mtime = sbi->s_record_time; + + if (!udf_stamp_to_time(&iinfo->i_crtime, + lets_to_cpu(efe->createTime))) + iinfo->i_crtime = sbi->s_record_time; + + if (!udf_stamp_to_time(&inode->i_ctime, + lets_to_cpu(efe->attrTime))) + inode->i_ctime = sbi->s_record_time; iinfo->i_unique = le64_to_cpu(efe->uniqueID); iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); diff --git a/fs/udf/super.c b/fs/udf/super.c index be0aa424b8f1..f4cdd530c65f 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -938,24 +938,19 @@ static int udf_find_fileset(struct super_block *sb, static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) { struct primaryVolDesc *pvoldesc; - time_t recording; - long recording_usec; struct ustr instr; struct ustr outstr; pvoldesc = (struct primaryVolDesc *)bh->b_data; - if (udf_stamp_to_time(&recording, &recording_usec, + if (udf_stamp_to_time(&UDF_SB(sb)->s_record_time, lets_to_cpu(pvoldesc->recordingDateAndTime))) { kernel_timestamp ts; ts = lets_to_cpu(pvoldesc->recordingDateAndTime); - udf_debug("recording time %ld/%ld, %04u/%02u/%02u" + udf_debug("recording time %04u/%02u/%02u" " %02u:%02u (%x)\n", - recording, recording_usec, ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone); - UDF_SB(sb)->s_record_time.tv_sec = recording; - UDF_SB(sb)->s_record_time.tv_nsec = recording_usec * 1000; } if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index cc15f58d497a..b277524fe608 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -222,7 +222,7 @@ extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); extern uint16_t udf_crc(const uint8_t *, uint32_t, uint16_t); /* udftime.c */ -extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp); -extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec); +extern struct timespec *udf_stamp_to_time(struct timespec *dest, kernel_timestamp src); +extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec src); #endif /* __UDF_DECL_H */ diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index ce595732ba6f..12fae6cd444c 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c @@ -85,7 +85,7 @@ extern struct timezone sys_tz; #define SECS_PER_HOUR (60 * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24) -time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) +struct timespec *udf_stamp_to_time(struct timespec *dest, kernel_timestamp src) { int yday; uint8_t type = src.typeAndTimezone >> 12; @@ -97,23 +97,20 @@ time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) offset = (offset >> 4); if (offset == -2047) /* unspecified offset */ offset = 0; - } else { + } else offset = 0; - } if ((src.year < EPOCH_YEAR) || (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { - *dest = -1; - *dest_usec = -1; return NULL; } - *dest = year_seconds[src.year - EPOCH_YEAR]; - *dest -= offset * 60; + dest->tv_sec = year_seconds[src.year - EPOCH_YEAR]; + dest->tv_sec -= offset * 60; yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1); - *dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; - *dest_usec = src.centiseconds * 10000 + - src.hundredsOfMicroseconds * 100 + src.microseconds; + dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; + dest->tv_nsec = 1000 * (src.centiseconds * 10000 + + src.hundredsOfMicroseconds * 100 + src.microseconds); return dest; } From 56774805d5eeecd3f1fb700603e593a35dc523c8 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 10 Feb 2008 11:25:31 +0100 Subject: [PATCH 19/41] udf: convert udf_stamp_to_time and udf_time_to_stamp to use timestamps * kernel_timestamp type was almost unused - only callers of udf_stamp_to_time and udf_time_to_stamp used it, so let these functions handle endianness internally and don't clutter code with conversions * rename udf_stamp_to_time to udf_disk_stamp_to_time and udf_time_to_stamp to udf_time_to_disk_stamp Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/inode.c | 45 ++++++++++++++++----------------------------- fs/udf/super.c | 22 ++++++++++------------ fs/udf/udfdecl.h | 5 +++-- fs/udf/udftime.c | 22 ++++++++++++---------- 4 files changed, 41 insertions(+), 53 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index a7646e9bdbde..2362bf0c6900 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1227,16 +1227,14 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - if (!udf_stamp_to_time(&inode->i_atime, - lets_to_cpu(fe->accessTime))) + if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime)) inode->i_atime = sbi->s_record_time; - if (!udf_stamp_to_time(&inode->i_mtime, - lets_to_cpu(fe->modificationTime))) + if (!udf_disk_stamp_to_time(&inode->i_mtime, + fe->modificationTime)) inode->i_mtime = sbi->s_record_time; - if (!udf_stamp_to_time(&inode->i_ctime, - lets_to_cpu(fe->attrTime))) + if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime)) inode->i_ctime = sbi->s_record_time; iinfo->i_unique = le64_to_cpu(fe->uniqueID); @@ -1247,20 +1245,17 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - if (!udf_stamp_to_time(&inode->i_atime, - lets_to_cpu(efe->accessTime))) + if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime)) inode->i_atime = sbi->s_record_time; - if (!udf_stamp_to_time(&inode->i_mtime, - lets_to_cpu(efe->modificationTime))) + if (!udf_disk_stamp_to_time(&inode->i_mtime, + efe->modificationTime)) inode->i_mtime = sbi->s_record_time; - if (!udf_stamp_to_time(&iinfo->i_crtime, - lets_to_cpu(efe->createTime))) + if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime)) iinfo->i_crtime = sbi->s_record_time; - if (!udf_stamp_to_time(&inode->i_ctime, - lets_to_cpu(efe->attrTime))) + if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime)) inode->i_ctime = sbi->s_record_time; iinfo->i_unique = le64_to_cpu(efe->uniqueID); @@ -1382,7 +1377,6 @@ static int udf_update_inode(struct inode *inode, int do_sync) uint32_t udfperms; uint16_t icbflags; uint16_t crclen; - kernel_timestamp cpu_time; int err = 0; struct udf_sb_info *sbi = UDF_SB(inode->i_sb); unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; @@ -1485,12 +1479,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >> (blocksize_bits - 9)); - if (udf_time_to_stamp(&cpu_time, inode->i_atime)) - fe->accessTime = cpu_to_lets(cpu_time); - if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) - fe->modificationTime = cpu_to_lets(cpu_time); - if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) - fe->attrTime = cpu_to_lets(cpu_time); + udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime); + udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime); + udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime); memset(&(fe->impIdent), 0, sizeof(regid)); strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; @@ -1525,14 +1516,10 @@ static int udf_update_inode(struct inode *inode, int do_sync) iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) iinfo->i_crtime = inode->i_ctime; - if (udf_time_to_stamp(&cpu_time, inode->i_atime)) - efe->accessTime = cpu_to_lets(cpu_time); - if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) - efe->modificationTime = cpu_to_lets(cpu_time); - if (udf_time_to_stamp(&cpu_time, iinfo->i_crtime)) - efe->createTime = cpu_to_lets(cpu_time); - if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) - efe->attrTime = cpu_to_lets(cpu_time); + udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime); + udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime); + udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime); + udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime); memset(&(efe->impIdent), 0, sizeof(regid)); strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); diff --git a/fs/udf/super.c b/fs/udf/super.c index f4cdd530c65f..4d2ecee1970b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -943,8 +943,8 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) pvoldesc = (struct primaryVolDesc *)bh->b_data; - if (udf_stamp_to_time(&UDF_SB(sb)->s_record_time, - lets_to_cpu(pvoldesc->recordingDateAndTime))) { + if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, + pvoldesc->recordingDateAndTime)) { kernel_timestamp ts; ts = lets_to_cpu(pvoldesc->recordingDateAndTime); udf_debug("recording time %04u/%02u/%02u" @@ -1589,7 +1589,6 @@ static void udf_open_lvid(struct super_block *sb) struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; if (bh) { - kernel_timestamp cpu_time; struct logicalVolIntegrityDesc *lvid = (struct logicalVolIntegrityDesc *)bh->b_data; struct logicalVolIntegrityDescImpUse *lvidiu = @@ -1597,8 +1596,8 @@ static void udf_open_lvid(struct super_block *sb) lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - lvid->recordingDateAndTime = cpu_to_lets(cpu_time); + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, + CURRENT_TIME); lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; lvid->descTag.descCRC = cpu_to_le16( @@ -1613,7 +1612,6 @@ static void udf_open_lvid(struct super_block *sb) static void udf_close_lvid(struct super_block *sb) { - kernel_timestamp cpu_time; struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; @@ -1628,8 +1626,8 @@ static void udf_close_lvid(struct super_block *sb) udf_sb_lvidiu(sbi); lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - lvid->recordingDateAndTime = cpu_to_lets(cpu_time); + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, + CURRENT_TIME); if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); @@ -1801,12 +1799,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) } if (!silent) { - kernel_timestamp ts; - udf_time_to_stamp(&ts, sbi->s_record_time); + timestamp ts; + udf_time_to_disk_stamp(&ts, sbi->s_record_time); udf_info("UDF: Mounting volume '%s', " "timestamp %04u/%02u/%02u %02u:%02u (%x)\n", - sbi->s_volume_ident, ts.year, ts.month, ts.day, - ts.hour, ts.minute, ts.typeAndTimezone); + sbi->s_volume_ident, le16_to_cpu(ts.year), ts.month, ts.day, + ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone)); } if (!(sb->s_flags & MS_RDONLY)) udf_open_lvid(sb); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index b277524fe608..2cb2f5de4245 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -222,7 +222,8 @@ extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); extern uint16_t udf_crc(const uint8_t *, uint32_t, uint16_t); /* udftime.c */ -extern struct timespec *udf_stamp_to_time(struct timespec *dest, kernel_timestamp src); -extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec src); +extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest, + timestamp src); +extern timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec src); #endif /* __UDF_DECL_H */ diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index 12fae6cd444c..5f811655c9b5 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c @@ -85,14 +85,16 @@ extern struct timezone sys_tz; #define SECS_PER_HOUR (60 * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24) -struct timespec *udf_stamp_to_time(struct timespec *dest, kernel_timestamp src) +struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src) { int yday; - uint8_t type = src.typeAndTimezone >> 12; + u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone); + u16 year = le16_to_cpu(src.year); + uint8_t type = typeAndTimezone >> 12; int16_t offset; if (type == 1) { - offset = src.typeAndTimezone << 4; + offset = typeAndTimezone << 4; /* sign extent offset */ offset = (offset >> 4); if (offset == -2047) /* unspecified offset */ @@ -100,21 +102,21 @@ struct timespec *udf_stamp_to_time(struct timespec *dest, kernel_timestamp src) } else offset = 0; - if ((src.year < EPOCH_YEAR) || - (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { + if ((year < EPOCH_YEAR) || + (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { return NULL; } - dest->tv_sec = year_seconds[src.year - EPOCH_YEAR]; + dest->tv_sec = year_seconds[year - EPOCH_YEAR]; dest->tv_sec -= offset * 60; - yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1); + yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1); dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; dest->tv_nsec = 1000 * (src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds); return dest; } -kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) +timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts) { long int days, rem, y; const unsigned short int *ip; @@ -125,7 +127,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) if (!dest) return NULL; - dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF); + dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF)); ts.tv_sec += offset * 60; days = ts.tv_sec / SECS_PER_DAY; @@ -148,7 +150,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) - LEAPS_THRU_END_OF(y - 1)); y = yg; } - dest->year = y; + dest->year = cpu_to_le16(y); ip = __mon_yday[__isleap(y)]; for (y = 11; days < (long int)ip[y]; --y) continue; From af15a298a49c9b5844cdaf70e10eb808e54ead2c Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 10 Feb 2008 11:29:10 +0100 Subject: [PATCH 20/41] udf: remove unneeded kernel_timestamp type remove now unneeded kernel_timestamp type with conversion functions Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/ecma_167.h | 13 ------------- fs/udf/super.c | 9 +++++---- fs/udf/udfend.h | 22 ---------------------- 3 files changed, 5 insertions(+), 39 deletions(-) diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h index 56387711589b..a0974df82b31 100644 --- a/fs/udf/ecma_167.h +++ b/fs/udf/ecma_167.h @@ -70,19 +70,6 @@ typedef struct { uint8_t microseconds; } __attribute__ ((packed)) timestamp; -typedef struct { - uint16_t typeAndTimezone; - int16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t centiseconds; - uint8_t hundredsOfMicroseconds; - uint8_t microseconds; -} __attribute__ ((packed)) kernel_timestamp; - /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ #define TIMESTAMP_TYPE_MASK 0xF000 #define TIMESTAMP_TYPE_CUT 0x0000 diff --git a/fs/udf/super.c b/fs/udf/super.c index 4d2ecee1970b..829ddfa5a148 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -945,12 +945,13 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, pvoldesc->recordingDateAndTime)) { - kernel_timestamp ts; - ts = lets_to_cpu(pvoldesc->recordingDateAndTime); +#ifdef UDFFS_DEBUG + timestamp *ts = &pvoldesc->recordingDateAndTime; udf_debug("recording time %04u/%02u/%02u" " %02u:%02u (%x)\n", - ts.year, ts.month, ts.day, ts.hour, - ts.minute, ts.typeAndTimezone); + le16_to_cpu(ts->year), ts->month, ts->day, ts->hour, + ts->minute, le16_to_cpu(ts->typeAndTimezone)); +#endif } if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h index c4bd1203f857..489f52fb428c 100644 --- a/fs/udf/udfend.h +++ b/fs/udf/udfend.h @@ -24,17 +24,6 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in) return out; } -static inline kernel_timestamp lets_to_cpu(timestamp in) -{ - kernel_timestamp out; - - memcpy(&out, &in, sizeof(timestamp)); - out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone); - out.year = le16_to_cpu(in.year); - - return out; -} - static inline short_ad lesa_to_cpu(short_ad in) { short_ad out; @@ -85,15 +74,4 @@ static inline kernel_extent_ad leea_to_cpu(extent_ad in) return out; } -static inline timestamp cpu_to_lets(kernel_timestamp in) -{ - timestamp out; - - memcpy(&out, &in, sizeof(timestamp)); - out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone); - out.year = cpu_to_le16(in.year); - - return out; -} - #endif /* __UDF_ENDIAN_H */ From 165923fa4590b0eb77bec31af383ea16b2d5868f Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 10 Feb 2008 11:33:08 +0100 Subject: [PATCH 21/41] udf: super.c reorganization reorganize few code blocks in super.c which were needlessly indented (and hard to read): so change from: rettype fun() { init; if (sth) { long block of code; } } to: rettype fun() { init; if (!sth) return; long block of code; } or from: rettype fun2() { init; while (sth) { init2(); if (sth2) { long block of code; } } } to: rettype fun2() { init; while (sth) { init2(); if (!sth2) continue; long block of code; } } Signed-off-by: Marcin Slusarz Signed-off-by: Jan Kara --- fs/udf/super.c | 554 ++++++++++++++++++++++++------------------------- 1 file changed, 271 insertions(+), 283 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 829ddfa5a148..17ba054faaa4 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -827,18 +827,18 @@ static void udf_find_anchor(struct super_block *sb) } for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { - if (sbi->s_anchor[i]) { - bh = udf_read_tagged(sb, sbi->s_anchor[i], - sbi->s_anchor[i], &ident); - if (!bh) + if (!sbi->s_anchor[i]) + continue; + bh = udf_read_tagged(sb, sbi->s_anchor[i], + sbi->s_anchor[i], &ident); + if (!bh) + sbi->s_anchor[i] = 0; + else { + brelse(bh); + if ((ident != TAG_IDENT_AVDP) && + (i || (ident != TAG_IDENT_FE && + ident != TAG_IDENT_EFE))) sbi->s_anchor[i] = 0; - else { - brelse(bh); - if ((ident != TAG_IDENT_AVDP) && - (i || (ident != TAG_IDENT_FE && - ident != TAG_IDENT_EFE))) - sbi->s_anchor[i] = 0; - } } } @@ -1020,128 +1020,118 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) { - struct partitionDesc *p; - int i; + struct partitionHeaderDesc *phd; + struct partitionDesc *p = (struct partitionDesc *)bh->b_data; struct udf_part_map *map; - struct udf_sb_info *sbi; - - p = (struct partitionDesc *)bh->b_data; - sbi = UDF_SB(sb); + struct udf_sb_info *sbi = UDF_SB(sb); + bool found = false; + int i; + u16 partitionNumber = le16_to_cpu(p->partitionNumber); for (i = 0; i < sbi->s_partitions; i++) { map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", - map->s_partition_num, - le16_to_cpu(p->partitionNumber)); - if (map->s_partition_num == - le16_to_cpu(p->partitionNumber)) { - map->s_partition_len = - le32_to_cpu(p->partitionLength); /* blocks */ - map->s_partition_root = - le32_to_cpu(p->partitionStartingLocation); - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) - map->s_partition_flags |= - UDF_PART_FLAG_READ_ONLY; - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) - map->s_partition_flags |= - UDF_PART_FLAG_WRITE_ONCE; - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) - map->s_partition_flags |= - UDF_PART_FLAG_REWRITABLE; - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) - map->s_partition_flags |= - UDF_PART_FLAG_OVERWRITABLE; - - if (!strcmp(p->partitionContents.ident, - PD_PARTITION_CONTENTS_NSR02) || - !strcmp(p->partitionContents.ident, - PD_PARTITION_CONTENTS_NSR03)) { - struct partitionHeaderDesc *phd; - - phd = (struct partitionHeaderDesc *) - (p->partitionContentsUse); - if (phd->unallocSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition), - .partitionReferenceNum = i, - }; - - map->s_uspace.s_table = - udf_iget(sb, loc); - if (!map->s_uspace.s_table) { - udf_debug("cannot load unallocSpaceTable (part %d)\n", i); - return 1; - } - map->s_partition_flags |= - UDF_PART_FLAG_UNALLOC_TABLE; - udf_debug("unallocSpaceTable (part %d) @ %ld\n", - i, map->s_uspace.s_table->i_ino); - } - if (phd->unallocSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = - udf_sb_alloc_bitmap(sb, i); - map->s_uspace.s_bitmap = bitmap; - if (bitmap != NULL) { - bitmap->s_extLength = - le32_to_cpu(phd->unallocSpaceBitmap.extLength); - bitmap->s_extPosition = - le32_to_cpu(phd->unallocSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; - udf_debug("unallocSpaceBitmap (part %d) @ %d\n", - i, bitmap->s_extPosition); - } - } - if (phd->partitionIntegrityTable.extLength) - udf_debug("partitionIntegrityTable (part %d)\n", i); - if (phd->freedSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition), - .partitionReferenceNum = i, - }; - - map->s_fspace.s_table = - udf_iget(sb, loc); - if (!map->s_fspace.s_table) { - udf_debug("cannot load freedSpaceTable (part %d)\n", i); - return 1; - } - map->s_partition_flags |= - UDF_PART_FLAG_FREED_TABLE; - udf_debug("freedSpaceTable (part %d) @ %ld\n", - i, map->s_fspace.s_table->i_ino); - } - if (phd->freedSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = - udf_sb_alloc_bitmap(sb, i); - map->s_fspace.s_bitmap = bitmap; - if (bitmap != NULL) { - bitmap->s_extLength = - le32_to_cpu(phd->freedSpaceBitmap.extLength); - bitmap->s_extPosition = - le32_to_cpu(phd->freedSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; - udf_debug("freedSpaceBitmap (part %d) @ %d\n", - i, bitmap->s_extPosition); - } - } - } + map->s_partition_num, partitionNumber); + found = map->s_partition_num == partitionNumber; + if (found) break; + } + + if (!found) { + udf_debug("Partition (%d) not found in partition map\n", + partitionNumber); + return 0; + } + + map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ + map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); + + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) + map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) + map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) + map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) + map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; + + udf_debug("Partition (%d:%d type %x) starts at physical %d, " + "block length %d\n", partitionNumber, i, + map->s_partition_type, map->s_partition_root, + map->s_partition_len); + + if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && + strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) + return 0; + + phd = (struct partitionHeaderDesc *)p->partitionContentsUse; + if (phd->unallocSpaceTable.extLength) { + kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu( + phd->unallocSpaceTable.extPosition), + .partitionReferenceNum = i, + }; + + map->s_uspace.s_table = udf_iget(sb, loc); + if (!map->s_uspace.s_table) { + udf_debug("cannot load unallocSpaceTable (part %d)\n", + i); + return 1; + } + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; + udf_debug("unallocSpaceTable (part %d) @ %ld\n", + i, map->s_uspace.s_table->i_ino); + } + + if (phd->unallocSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, i); + map->s_uspace.s_bitmap = bitmap; + if (bitmap != NULL) { + bitmap->s_extLength = le32_to_cpu( + phd->unallocSpaceBitmap.extLength); + bitmap->s_extPosition = le32_to_cpu( + phd->unallocSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; + udf_debug("unallocSpaceBitmap (part %d) @ %d\n", + i, bitmap->s_extPosition); } } - if (i == sbi->s_partitions) - udf_debug("Partition (%d) not found in partition map\n", - le16_to_cpu(p->partitionNumber)); - else - udf_debug("Partition (%d:%d type %x) starts at physical %d, " - "block length %d\n", - le16_to_cpu(p->partitionNumber), i, - map->s_partition_type, - map->s_partition_root, - map->s_partition_len); + + if (phd->partitionIntegrityTable.extLength) + udf_debug("partitionIntegrityTable (part %d)\n", i); + + if (phd->freedSpaceTable.extLength) { + kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu( + phd->freedSpaceTable.extPosition), + .partitionReferenceNum = i, + }; + + map->s_fspace.s_table = udf_iget(sb, loc); + if (!map->s_fspace.s_table) { + udf_debug("cannot load freedSpaceTable (part %d)\n", i); + return 1; + } + + map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; + udf_debug("freedSpaceTable (part %d) @ %ld\n", + i, map->s_fspace.s_table->i_ino); + } + + if (phd->freedSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, i); + map->s_fspace.s_bitmap = bitmap; + if (bitmap != NULL) { + bitmap->s_extLength = le32_to_cpu( + phd->freedSpaceBitmap.extLength); + bitmap->s_extPosition = le32_to_cpu( + phd->freedSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; + udf_debug("freedSpaceBitmap (part %d) @ %d\n", + i, bitmap->s_extPosition); + } + } + return 0; } @@ -1215,19 +1205,17 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, map->s_type_specific.s_sparing. s_spar_map[j] = bh2; - if (bh2 != NULL) { - st = (struct sparingTable *) - bh2->b_data; - if (ident != 0 || strncmp( - st->sparingIdent.ident, - UDF_ID_SPARING, - strlen(UDF_ID_SPARING))) { - brelse(bh2); - map->s_type_specific. - s_sparing. - s_spar_map[j] = - NULL; - } + if (bh2 == NULL) + continue; + + st = (struct sparingTable *)bh2->b_data; + if (ident != 0 || strncmp( + st->sparingIdent.ident, + UDF_ID_SPARING, + strlen(UDF_ID_SPARING))) { + brelse(bh2); + map->s_type_specific.s_sparing. + s_spar_map[j] = NULL; } } map->s_partition_func = udf_get_pblock_spar15; @@ -1392,40 +1380,40 @@ static int udf_process_sequence(struct super_block *sb, long block, brelse(bh); } for (i = 0; i < VDS_POS_LENGTH; i++) { - if (vds[i].block) { - bh = udf_read_tagged(sb, vds[i].block, vds[i].block, - &ident); + if (!vds[i].block) + continue; - if (i == VDS_POS_PRIMARY_VOL_DESC) { - udf_load_pvoldesc(sb, bh); - } else if (i == VDS_POS_LOGICAL_VOL_DESC) { - if (udf_load_logicalvol(sb, bh, fileset)) { - brelse(bh); - return 1; - } - } else if (i == VDS_POS_PARTITION_DESC) { - struct buffer_head *bh2 = NULL; - if (udf_load_partdesc(sb, bh)) { - brelse(bh); - return 1; - } - for (j = vds[i].block + 1; - j < vds[VDS_POS_TERMINATING_DESC].block; - j++) { - bh2 = udf_read_tagged(sb, j, j, &ident); - gd = (struct generic_desc *)bh2->b_data; - if (ident == TAG_IDENT_PD) - if (udf_load_partdesc(sb, - bh2)) { - brelse(bh); - brelse(bh2); - return 1; - } - brelse(bh2); - } + bh = udf_read_tagged(sb, vds[i].block, vds[i].block, + &ident); + + if (i == VDS_POS_PRIMARY_VOL_DESC) + udf_load_pvoldesc(sb, bh); + else if (i == VDS_POS_LOGICAL_VOL_DESC) { + if (udf_load_logicalvol(sb, bh, fileset)) { + brelse(bh); + return 1; + } + } else if (i == VDS_POS_PARTITION_DESC) { + struct buffer_head *bh2 = NULL; + if (udf_load_partdesc(sb, bh)) { + brelse(bh); + return 1; + } + for (j = vds[i].block + 1; + j < vds[VDS_POS_TERMINATING_DESC].block; + j++) { + bh2 = udf_read_tagged(sb, j, j, &ident); + gd = (struct generic_desc *)bh2->b_data; + if (ident == TAG_IDENT_PD) + if (udf_load_partdesc(sb, bh2)) { + brelse(bh); + brelse(bh2); + return 1; + } + brelse(bh2); } - brelse(bh); } + brelse(bh); } return 0; @@ -1437,6 +1425,7 @@ static int udf_process_sequence(struct super_block *sb, long block, static int udf_check_valid(struct super_block *sb, int novrs, int silent) { long block; + struct udf_sb_info *sbi; if (novrs) { udf_debug("Validity check skipped because of novrs option\n"); @@ -1444,18 +1433,16 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) } /* Check that it is NSR02 compliant */ /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ - else { - block = udf_vrs(sb, silent); - if (block == -1) { - struct udf_sb_info *sbi = UDF_SB(sb); - udf_debug("Failed to read byte 32768. Assuming open " - "disc. Skipping validity check\n"); - if (!sbi->s_last_block) - sbi->s_last_block = udf_get_last_block(sb); - return 0; - } else - return !block; - } + block = udf_vrs(sb, silent); + if (block != -1) + return !block; + + sbi = UDF_SB(sb); + udf_debug("Failed to read byte 32768. Assuming open " + "disc. Skipping validity check\n"); + if (!sbi->s_last_block) + sbi->s_last_block = udf_get_last_block(sb); + return 0; } static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) @@ -1474,6 +1461,7 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { if (!sbi->s_anchor[i]) continue; + bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], &ident); if (!bh) @@ -1515,72 +1503,73 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) for (i = 0; i < sbi->s_partitions; i++) { kernel_lb_addr uninitialized_var(ino); struct udf_part_map *map = &sbi->s_partmaps[i]; - switch (map->s_partition_type) { - case UDF_VIRTUAL_MAP15: - case UDF_VIRTUAL_MAP20: - if (!sbi->s_last_block) { - sbi->s_last_block = udf_get_last_block(sb); - udf_find_anchor(sb); - } - if (!sbi->s_last_block) { - udf_debug("Unable to determine Lastblock (For " - "Virtual Partition)\n"); - return 1; - } + if (map->s_partition_type != UDF_VIRTUAL_MAP15 && + map->s_partition_type != UDF_VIRTUAL_MAP20) + continue; - for (j = 0; j < sbi->s_partitions; j++) { - struct udf_part_map *map2 = &sbi->s_partmaps[j]; - if (j != i && - map->s_volumeseqnum == - map2->s_volumeseqnum && - map->s_partition_num == - map2->s_partition_num) { - ino.partitionReferenceNum = j; - ino.logicalBlockNum = - sbi->s_last_block - - map2->s_partition_root; - break; - } - } - - if (j == sbi->s_partitions) - return 1; - - sbi->s_vat_inode = udf_iget(sb, ino); - if (!sbi->s_vat_inode) - return 1; - - if (map->s_partition_type == UDF_VIRTUAL_MAP15) { - map->s_type_specific.s_virtual.s_start_offset = - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - 36) >> 2; - } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { - uint32_t pos; - struct virtualAllocationTable20 *vat20; - - pos = udf_block_map(sbi->s_vat_inode, 0); - bh = sb_bread(sb, pos); - if (!bh) - return 1; - vat20 = (struct virtualAllocationTable20 *) - bh->b_data + - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_start_offset = - le16_to_cpu(vat20->lengthHeader) + - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - - map->s_type_specific.s_virtual. - s_start_offset) >> 2; - brelse(bh); - } - map->s_partition_root = udf_get_pblock(sb, 0, i, 0); - map->s_partition_len = - sbi->s_partmaps[ino.partitionReferenceNum]. - s_partition_len; + if (!sbi->s_last_block) { + sbi->s_last_block = udf_get_last_block(sb); + udf_find_anchor(sb); } + + if (!sbi->s_last_block) { + udf_debug("Unable to determine Lastblock (For " + "Virtual Partition)\n"); + return 1; + } + + for (j = 0; j < sbi->s_partitions; j++) { + struct udf_part_map *map2 = &sbi->s_partmaps[j]; + if (j != i && + map->s_volumeseqnum == + map2->s_volumeseqnum && + map->s_partition_num == + map2->s_partition_num) { + ino.partitionReferenceNum = j; + ino.logicalBlockNum = + sbi->s_last_block - + map2->s_partition_root; + break; + } + } + + if (j == sbi->s_partitions) + return 1; + + sbi->s_vat_inode = udf_iget(sb, ino); + if (!sbi->s_vat_inode) + return 1; + + if (map->s_partition_type == UDF_VIRTUAL_MAP15) { + map->s_type_specific.s_virtual.s_start_offset = + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - 36) >> 2; + } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { + uint32_t pos; + struct virtualAllocationTable20 *vat20; + + pos = udf_block_map(sbi->s_vat_inode, 0); + bh = sb_bread(sb, pos); + if (!bh) + return 1; + vat20 = (struct virtualAllocationTable20 *) + bh->b_data + + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_start_offset = + le16_to_cpu(vat20->lengthHeader) + + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - + map->s_type_specific.s_virtual. + s_start_offset) >> 2; + brelse(bh); + } + map->s_partition_root = udf_get_pblock(sb, 0, i, 0); + map->s_partition_len = + sbi->s_partmaps[ino.partitionReferenceNum]. + s_partition_len; } return 0; } @@ -1589,26 +1578,26 @@ static void udf_open_lvid(struct super_block *sb) { struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; - if (bh) { - struct logicalVolIntegrityDesc *lvid = - (struct logicalVolIntegrityDesc *)bh->b_data; - struct logicalVolIntegrityDescImpUse *lvidiu = - udf_sb_lvidiu(sbi); + struct logicalVolIntegrityDesc *lvid; + struct logicalVolIntegrityDescImpUse *lvidiu; + if (!bh) + return; - lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, - CURRENT_TIME); - lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; + lvid = (struct logicalVolIntegrityDesc *)bh->b_data; + lvidiu = udf_sb_lvidiu(sbi); - lvid->descTag.descCRC = cpu_to_le16( - udf_crc((char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength), - 0)); + lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, + CURRENT_TIME); + lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; - lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); - mark_buffer_dirty(bh); - } + lvid->descTag.descCRC = cpu_to_le16( + udf_crc((char *)lvid + sizeof(tag), + le16_to_cpu(lvid->descTag.descCRCLength), 0)); + + lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + mark_buffer_dirty(bh); } static void udf_close_lvid(struct super_block *sb) @@ -1616,36 +1605,35 @@ static void udf_close_lvid(struct super_block *sb) struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; + struct logicalVolIntegrityDescImpUse *lvidiu; if (!bh) return; lvid = (struct logicalVolIntegrityDesc *)bh->b_data; - if (lvid->integrityType == LVID_INTEGRITY_TYPE_OPEN) { - struct logicalVolIntegrityDescImpUse *lvidiu = - udf_sb_lvidiu(sbi); - lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, - CURRENT_TIME); - if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) - lvidiu->maxUDFWriteRev = - cpu_to_le16(UDF_MAX_WRITE_VERSION); - if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) - lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); - if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) - lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); - lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); + if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN) + return; - lvid->descTag.descCRC = cpu_to_le16( - udf_crc((char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength), - 0)); + lvidiu = udf_sb_lvidiu(sbi); + lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); + if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) + lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); + if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) + lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); + if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) + lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); + lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); - lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); - mark_buffer_dirty(bh); - } + lvid->descTag.descCRC = cpu_to_le16( + udf_crc((char *)lvid + sizeof(tag), + le16_to_cpu(lvid->descTag.descCRCLength), + 0)); + + lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + mark_buffer_dirty(bh); } static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) From 200a3592cda7bfc010d30c0b1eb8eff3791e9ba9 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Mar 2008 13:03:09 +0100 Subject: [PATCH 22/41] udf: Mark udf_process_sequence() as noinline Mark udf_process_sequence() as noinline since stack usage is terrible otherwise. Signed-off-by: Jan Kara --- fs/udf/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 17ba054faaa4..bb8d866deb3f 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1292,7 +1292,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ -static int udf_process_sequence(struct super_block *sb, long block, +static noinline int udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_lb_addr *fileset) { struct buffer_head *bh = NULL; From 9bf2c6b834f4caad82b3e2d962c266153d39e411 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Mar 2008 13:10:29 +0100 Subject: [PATCH 23/41] udf: Remove checking of existence of filename in udf_add_entry() We don't have to check whether a directory entry already exists in a directory when creating a new one since we've already checked that earlier by lookup and we are holding directory i_mutex all the time. Signed-off-by: Jan Kara --- fs/udf/namei.c | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index ac7f72779e93..e9f587201e17 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -303,11 +303,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, { struct super_block *sb = dir->i_sb; struct fileIdentDesc *fi = NULL; - char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; + char name[UDF_NAME_LEN]; int namelen; loff_t f_pos; - int flen; - char *nameptr; loff_t size = udf_ext0_offset(dir) + dir->i_size; int nfidlen; uint8_t lfi; @@ -385,26 +383,6 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, liu = le16_to_cpu(cfi->lengthOfImpUse); lfi = cfi->lengthFileIdent; - if (fibh->sbh == fibh->ebh) - nameptr = fi->fileIdent + liu; - else { - int poffset; /* Unpaded ending offset */ - - poffset = fibh->soffset + sizeof(struct fileIdentDesc) + - liu + lfi; - - if (poffset >= lfi) - nameptr = (char *)(fibh->ebh->b_data + - poffset - lfi); - else { - nameptr = fname; - memcpy(nameptr, fi->fileIdent + liu, - lfi - poffset); - memcpy(nameptr + lfi - poffset, - fibh->ebh->b_data, poffset); - } - } - if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) { @@ -423,20 +401,6 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, } } } - - if (!lfi || !dentry) - continue; - - flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); - if (flen && udf_match(flen, fname, dentry->d_name.len, - dentry->d_name.name)) { - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); - brelse(epos.bh); - *err = -EEXIST; - return NULL; - } } add: From b80697c14dcacd83ed1b78e26ad93b25ecc52c5e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Mar 2008 14:14:05 +0100 Subject: [PATCH 24/41] udf: Remove declarations of arrays of size UDF_NAME_LEN (256 bytes) There are several places in UDF where we declared temporary arrays of UDF_NAME_LEN bytes on stack. This is not nice to stack usage so this patch changes those places to use kmalloc() instead. Also clean up bail-out paths in those functions when we are changing them. Signed-off-by: Jan Kara --- fs/udf/dir.c | 57 +++++++++++----------- fs/udf/namei.c | 128 +++++++++++++++++++++++++------------------------ 2 files changed, 93 insertions(+), 92 deletions(-) diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 31feef916fb7..62dc270c69d1 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -39,13 +39,13 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, filldir_t filldir, void *dirent) { - struct udf_fileident_bh fibh; + struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL}; struct fileIdentDesc *fi = NULL; struct fileIdentDesc cfi; int block, iblock; loff_t nf_pos = (filp->f_pos - 1) << 2; int flen; - char fname[UDF_NAME_LEN]; + char *fname = NULL; char *nameptr; uint16_t liu; uint8_t lfi; @@ -54,23 +54,32 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, kernel_lb_addr eloc; uint32_t elen; sector_t offset; - int i, num; + int i, num, ret = 0; unsigned int dt_type; struct extent_position epos = { NULL, 0, {0, 0} }; struct udf_inode_info *iinfo; if (nf_pos >= size) - return 0; + goto out; + + fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!fname) { + ret = -ENOMEM; + goto out; + } if (nf_pos == 0) nf_pos = udf_ext0_offset(dir); fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); iinfo = UDF_I(dir); - if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { - fibh.sbh = fibh.ebh = NULL; - } else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, - &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) { + if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, + &epos, &eloc, &elen, &offset) + != (EXT_RECORDED_ALLOCATED >> 30)) { + ret = -ENOENT; + goto out; + } block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -83,8 +92,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, } if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { - brelse(epos.bh); - return -EIO; + ret = -EIO; + goto out; } if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { @@ -105,9 +114,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, brelse(bha[i]); } } - } else { - brelse(epos.bh); - return -ENOENT; } while (nf_pos < size) { @@ -115,13 +121,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset); - if (!fi) { - if (fibh.sbh != fibh.ebh) - brelse(fibh.ebh); - brelse(fibh.sbh); - brelse(epos.bh); - return 0; - } + if (!fi) + goto out; liu = le16_to_cpu(cfi.lengthOfImpUse); lfi = cfi.lengthFileIdent; @@ -167,25 +168,21 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, dt_type = DT_UNKNOWN; } - if (flen) { - if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) { - if (fibh.sbh != fibh.ebh) - brelse(fibh.ebh); - brelse(fibh.sbh); - brelse(epos.bh); - return 0; - } - } + if (flen && filldir(dirent, fname, flen, filp->f_pos, + iblock, dt_type) < 0) + goto out; } /* end while */ filp->f_pos = (nf_pos >> 2) + 1; +out: if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); brelse(epos.bh); + kfree(fname); - return 0; + return ret; } static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index e9f587201e17..68686b79650a 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -149,7 +149,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, struct fileIdentDesc *fi = NULL; loff_t f_pos; int block, flen; - char fname[UDF_NAME_LEN]; + char *fname = NULL; char *nameptr; uint8_t lfi; uint16_t liu; @@ -163,12 +163,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, size = udf_ext0_offset(dir) + dir->i_size; f_pos = udf_ext0_offset(dir); + fibh->sbh = fibh->ebh = NULL; fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); - if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) - fibh->sbh = fibh->ebh = NULL; - else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, - &epos, &eloc, &elen, &offset) == - (EXT_RECORDED_ALLOCATED >> 30)) { + if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, + &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) + goto out_err; block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -179,25 +179,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, offset = 0; fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); - if (!fibh->sbh) { - brelse(epos.bh); - return NULL; - } - } else { - brelse(epos.bh); - return NULL; + if (!fibh->sbh) + goto out_err; } + fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!fname) + goto out_err; + while (f_pos < size) { fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset); - if (!fi) { - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); - brelse(epos.bh); - return NULL; - } + if (!fi) + goto out_err; liu = le16_to_cpu(cfi->lengthOfImpUse); lfi = cfi->lengthFileIdent; @@ -237,18 +231,20 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); if (flen && udf_match(flen, fname, dentry->d_name.len, - dentry->d_name.name)) { - brelse(epos.bh); - return fi; - } + dentry->d_name.name)) + goto out_ok; } +out_err: + fi = NULL; if (fibh->sbh != fibh->ebh) brelse(fibh->ebh); brelse(fibh->sbh); +out_ok: brelse(epos.bh); + kfree(fname); - return NULL; + return fi; } static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, @@ -303,7 +299,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, { struct super_block *sb = dir->i_sb; struct fileIdentDesc *fi = NULL; - char name[UDF_NAME_LEN]; + char *name = NULL; int namelen; loff_t f_pos; loff_t size = udf_ext0_offset(dir) + dir->i_size; @@ -317,16 +313,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, struct extent_position epos = {}; struct udf_inode_info *dinfo; + fibh->sbh = fibh->ebh = NULL; + name = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!name) { + *err = -ENOMEM; + goto out_err; + } + if (dentry) { if (!dentry->d_name.len) { *err = -EINVAL; - return NULL; + goto out_err; } namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len); if (!namelen) { *err = -ENAMETOOLONG; - return NULL; + goto out_err; } } else { namelen = 0; @@ -338,11 +341,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); dinfo = UDF_I(dir); - if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) - fibh->sbh = fibh->ebh = NULL; - else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, - &epos, &eloc, &elen, &offset) == - (EXT_RECORDED_ALLOCATED >> 30)) { + if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, + &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { + block = udf_get_lb_pblock(dir->i_sb, + dinfo->i_location, 0); + fibh->soffset = fibh->eoffset = sb->s_blocksize; + goto add; + } block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -354,17 +360,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); if (!fibh->sbh) { - brelse(epos.bh); *err = -EIO; - return NULL; + goto out_err; } block = dinfo->i_location.logicalBlockNum; - } else { - block = udf_get_lb_pblock(dir->i_sb, dinfo->i_location, 0); - fibh->sbh = fibh->ebh = NULL; - fibh->soffset = fibh->eoffset = sb->s_blocksize; - goto add; } while (f_pos < size) { @@ -372,12 +372,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, &elen, &offset); if (!fi) { - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); - brelse(epos.bh); *err = -EIO; - return NULL; + goto out_err; } liu = le16_to_cpu(cfi->lengthOfImpUse); @@ -386,7 +382,6 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) { - brelse(epos.bh); cfi->descTag.tagSerialNum = cpu_to_le16(1); cfi->fileVersionNum = cpu_to_le16(1); cfi->fileCharacteristics = 0; @@ -394,10 +389,10 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, cfi->lengthOfImpUse = cpu_to_le16(0); if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) - return fi; + goto out_ok; else { *err = -EIO; - return NULL; + goto out_err; } } } @@ -427,7 +422,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err); if (!fibh->sbh) - return NULL; + goto out_err; epos.block = dinfo->i_location; epos.offset = udf_file_entry_alloc_offset(dir); /* Load extent udf_expand_dir_adinicb() has created */ @@ -468,11 +463,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, dir->i_sb->s_blocksize_bits); fibh->ebh = udf_bread(dir, f_pos >> dir->i_sb->s_blocksize_bits, 1, err); - if (!fibh->ebh) { - brelse(epos.bh); - brelse(fibh->sbh); - return NULL; - } + if (!fibh->ebh) + goto out_err; if (!fibh->soffset) { if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == @@ -503,20 +495,25 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, cfi->lengthFileIdent = namelen; cfi->lengthOfImpUse = cpu_to_le16(0); if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { - brelse(epos.bh); dir->i_size += nfidlen; if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) dinfo->i_lenAlloc += nfidlen; mark_inode_dirty(dir); - return fi; + goto out_ok; } else { - brelse(epos.bh); - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); *err = -EIO; - return NULL; + goto out_err; } + +out_err: + fi = NULL; + if (fibh->sbh != fibh->ebh) + brelse(fibh->ebh); + brelse(fibh->sbh); +out_ok: + brelse(epos.bh); + kfree(name); + return fi; } static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, @@ -871,7 +868,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, char *ea; int err; int block; - char name[UDF_NAME_LEN]; + char *name = NULL; int namelen; struct buffer_head *bh; struct udf_inode_info *iinfo; @@ -881,6 +878,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, if (!inode) goto out; + name = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!name) { + err = -ENOMEM; + goto out_no_entry; + } + iinfo = UDF_I(inode); inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_data.a_ops = &udf_symlink_aops; @@ -1020,6 +1023,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, err = 0; out: + kfree(name); unlock_kernel(); return err; From d0db181c072259c21a375b290a4574e5ce6d2b5f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 5 Mar 2008 00:03:36 +0100 Subject: [PATCH 25/41] udf: fix anchor point detection According to ECMA 167 rev. 3 (see 3/8.4.2.1), Anchor Volume Descriptor Pointer should be recorded at two or more anchor points located at sectors 256, N, N - 256, where N - is a largest logical sector number at volume space. So we should always try to detect N on UDF volume before trying to find Anchor Volume Descriptor (i.e. calling to udf_find_anchor()). That said, all this patch does is updates the s_last_block even if the udf_vrs() returns positive value. Originally written and tested by Yuri Per, ported on latest mainline by me. Signed-off-by: Yuri Per Signed-off-by: Pavel Emelyanov Cc: Max Lyadvinsky Cc: Vladimir Simonov Cc: Andrew Neporada Cc: Kirill Korotaev Signed-off-by: Jan Kara --- fs/udf/super.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index bb8d866deb3f..137153c5005b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1425,7 +1425,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, static int udf_check_valid(struct super_block *sb, int novrs, int silent) { long block; - struct udf_sb_info *sbi; + struct udf_sb_info *sbi = UDF_SB(sb); if (novrs) { udf_debug("Validity check skipped because of novrs option\n"); @@ -1434,15 +1434,12 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) /* Check that it is NSR02 compliant */ /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ block = udf_vrs(sb, silent); - if (block != -1) - return !block; - - sbi = UDF_SB(sb); - udf_debug("Failed to read byte 32768. Assuming open " - "disc. Skipping validity check\n"); - if (!sbi->s_last_block) + if (block == -1) + udf_debug("Failed to read byte 32768. Assuming open " + "disc. Skipping validity check\n"); + if (block && !sbi->s_last_block) sbi->s_last_block = udf_get_last_block(sb); - return 0; + return !block; } static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) From c0eb31ed130ab18e1858179a644e39aee2355a13 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 1 Apr 2008 16:50:35 +0200 Subject: [PATCH 26/41] udf: Cleanup volume descriptor sequence processing Cleanup processing of volume descriptor sequence so that it is more readable, make code handle errors (e.g. media problems) better. Signed-off-by: Jan Kara --- fs/udf/super.c | 135 +++++++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 54 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 137153c5005b..500d1e4cc1c7 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -85,16 +85,12 @@ static int udf_remount_fs(struct super_block *, int *, char *); static int udf_check_valid(struct super_block *, int, int); static int udf_vrs(struct super_block *sb, int silent); static int udf_load_partition(struct super_block *, kernel_lb_addr *); -static int udf_load_logicalvol(struct super_block *, struct buffer_head *, - kernel_lb_addr *); static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); static void udf_find_anchor(struct super_block *); static int udf_find_fileset(struct super_block *, kernel_lb_addr *, kernel_lb_addr *); -static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *); -static int udf_load_partdesc(struct super_block *, struct buffer_head *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); @@ -935,11 +931,18 @@ static int udf_find_fileset(struct super_block *sb, return 1; } -static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) +static int udf_load_pvoldesc(struct super_block *sb, sector_t block) { struct primaryVolDesc *pvoldesc; struct ustr instr; struct ustr outstr; + struct buffer_head *bh; + uint16_t ident; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + return 1; + BUG_ON(ident != TAG_IDENT_PVD); pvoldesc = (struct primaryVolDesc *)bh->b_data; @@ -965,6 +968,9 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) if (udf_CS0toUTF8(&outstr, &instr)) udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); + + brelse(bh); + return 0; } static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, @@ -1018,16 +1024,27 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) return bitmap; } -static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) +static int udf_load_partdesc(struct super_block *sb, sector_t block) { + struct buffer_head *bh; struct partitionHeaderDesc *phd; - struct partitionDesc *p = (struct partitionDesc *)bh->b_data; + struct partitionDesc *p; struct udf_part_map *map; struct udf_sb_info *sbi = UDF_SB(sb); bool found = false; int i; - u16 partitionNumber = le16_to_cpu(p->partitionNumber); + uint16_t partitionNumber; + uint16_t ident; + int ret = 0; + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + return 1; + if (ident != TAG_IDENT_PD) + goto out_bh; + + p = (struct partitionDesc *)bh->b_data; + partitionNumber = le16_to_cpu(p->partitionNumber); for (i = 0; i < sbi->s_partitions; i++) { map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", @@ -1040,7 +1057,7 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) if (!found) { udf_debug("Partition (%d) not found in partition map\n", partitionNumber); - return 0; + goto out_bh; } map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ @@ -1062,7 +1079,7 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) - return 0; + goto out_bh; phd = (struct partitionHeaderDesc *)p->partitionContentsUse; if (phd->unallocSpaceTable.extLength) { @@ -1076,7 +1093,8 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) if (!map->s_uspace.s_table) { udf_debug("cannot load unallocSpaceTable (part %d)\n", i); - return 1; + ret = 1; + goto out_bh; } map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; udf_debug("unallocSpaceTable (part %d) @ %ld\n", @@ -1110,7 +1128,8 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) map->s_fspace.s_table = udf_iget(sb, loc); if (!map->s_fspace.s_table) { udf_debug("cannot load freedSpaceTable (part %d)\n", i); - return 1; + ret = 1; + goto out_bh; } map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; @@ -1132,10 +1151,12 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) } } - return 0; +out_bh: + brelse(bh); + return ret; } -static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, +static int udf_load_logicalvol(struct super_block *sb, sector_t block, kernel_lb_addr *fileset) { struct logicalVolDesc *lvd; @@ -1143,12 +1164,21 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, uint8_t type; struct udf_sb_info *sbi = UDF_SB(sb); struct genericPartitionMap *gpm; + uint16_t ident; + struct buffer_head *bh; + int ret = 0; + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + return 1; + BUG_ON(ident != TAG_IDENT_LVD); lvd = (struct logicalVolDesc *)bh->b_data; i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); - if (i != 0) - return i; + if (i != 0) { + ret = i; + goto out_bh; + } for (i = 0, offset = 0; i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); @@ -1187,7 +1217,6 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { uint32_t loc; - uint16_t ident; struct sparingTable *st; struct sparablePartitionMap *spm = (struct sparablePartitionMap *)gpm; @@ -1243,7 +1272,9 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, if (lvd->integritySeqExt.extLength) udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); - return 0; +out_bh: + brelse(bh); + return ret; } /* @@ -1301,19 +1332,25 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, struct generic_desc *gd; struct volDescPtr *vdp; int done = 0; - int i, j; uint32_t vdsn; uint16_t ident; long next_s = 0, next_e = 0; memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); - /* Read the main descriptor sequence */ + /* + * Read the main descriptor sequence and find which descriptors + * are in it. + */ for (; (!done && block <= lastblock); block++) { bh = udf_read_tagged(sb, block, block, &ident); - if (!bh) - break; + if (!bh) { + printk(KERN_ERR "udf: Block %Lu of volume descriptor " + "sequence is corrupted or we could not read " + "it.\n", (unsigned long long)block); + return 1; + } /* Process each descriptor (ISO 13346 3/8.3-8.4) */ gd = (struct generic_desc *)bh->b_data; @@ -1379,41 +1416,31 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, } brelse(bh); } - for (i = 0; i < VDS_POS_LENGTH; i++) { - if (!vds[i].block) - continue; + /* + * Now read interesting descriptors again and process them + * in a suitable order + */ + if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { + printk(KERN_ERR "udf: Primary Volume Descriptor not found!\n"); + return 1; + } + if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block)) + return 1; - bh = udf_read_tagged(sb, vds[i].block, vds[i].block, - &ident); + if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb, + vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset)) + return 1; - if (i == VDS_POS_PRIMARY_VOL_DESC) - udf_load_pvoldesc(sb, bh); - else if (i == VDS_POS_LOGICAL_VOL_DESC) { - if (udf_load_logicalvol(sb, bh, fileset)) { - brelse(bh); + if (vds[VDS_POS_PARTITION_DESC].block) { + /* + * We rescan the whole descriptor sequence to find + * partition descriptor blocks and process them. + */ + for (block = vds[VDS_POS_PARTITION_DESC].block; + block < vds[VDS_POS_TERMINATING_DESC].block; + block++) + if (udf_load_partdesc(sb, block)) return 1; - } - } else if (i == VDS_POS_PARTITION_DESC) { - struct buffer_head *bh2 = NULL; - if (udf_load_partdesc(sb, bh)) { - brelse(bh); - return 1; - } - for (j = vds[i].block + 1; - j < vds[VDS_POS_TERMINATING_DESC].block; - j++) { - bh2 = udf_read_tagged(sb, j, j, &ident); - gd = (struct generic_desc *)bh2->b_data; - if (ident == TAG_IDENT_PD) - if (udf_load_partdesc(sb, bh2)) { - brelse(bh); - brelse(bh2); - return 1; - } - brelse(bh2); - } - } - brelse(bh); } return 0; From 2e0838fd0c0b8f0753a4be9af9f9712c4be881e1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 1 Apr 2008 18:08:51 +0200 Subject: [PATCH 27/41] udf: Improve error recovery on mount Report error when we fail to allocate memory for a bitmap and properly release allocated memory and inodes for all the partitions in case of mount failure and umount. Signed-off-by: Jan Kara --- fs/udf/super.c | 94 ++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 500d1e4cc1c7..d50e3f5c46e8 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1103,16 +1103,18 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) if (phd->unallocSpaceBitmap.extLength) { struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, i); - map->s_uspace.s_bitmap = bitmap; - if (bitmap != NULL) { - bitmap->s_extLength = le32_to_cpu( - phd->unallocSpaceBitmap.extLength); - bitmap->s_extPosition = le32_to_cpu( - phd->unallocSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; - udf_debug("unallocSpaceBitmap (part %d) @ %d\n", - i, bitmap->s_extPosition); + if (!bitmap) { + ret = 1; + goto out_bh; } + map->s_uspace.s_bitmap = bitmap; + bitmap->s_extLength = le32_to_cpu( + phd->unallocSpaceBitmap.extLength); + bitmap->s_extPosition = le32_to_cpu( + phd->unallocSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; + udf_debug("unallocSpaceBitmap (part %d) @ %d\n", i, + bitmap->s_extPosition); } if (phd->partitionIntegrityTable.extLength) @@ -1139,19 +1141,22 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) if (phd->freedSpaceBitmap.extLength) { struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, i); - map->s_fspace.s_bitmap = bitmap; - if (bitmap != NULL) { - bitmap->s_extLength = le32_to_cpu( - phd->freedSpaceBitmap.extLength); - bitmap->s_extPosition = le32_to_cpu( - phd->freedSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; - udf_debug("freedSpaceBitmap (part %d) @ %d\n", - i, bitmap->s_extPosition); + if (!bitmap) { + ret = 1; + goto out_bh; } + map->s_fspace.s_bitmap = bitmap; + bitmap->s_extLength = le32_to_cpu( + phd->freedSpaceBitmap.extLength); + bitmap->s_extPosition = le32_to_cpu( + phd->freedSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; + udf_debug("freedSpaceBitmap (part %d) @ %d\n", i, + bitmap->s_extPosition); } out_bh: + /* In case loading failed, we handle cleanup in udf_fill_super */ brelse(bh); return ret; } @@ -1677,6 +1682,23 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) vfree(bitmap); } +static void udf_free_partition(struct udf_part_map *map) +{ + int i; + + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) + iput(map->s_uspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) + iput(map->s_fspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) + udf_sb_free_bitmap(map->s_uspace.s_bitmap); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) + udf_sb_free_bitmap(map->s_fspace.s_bitmap); + if (map->s_partition_type == UDF_SPARABLE_MAP15) + for (i = 0; i < 4; i++) + brelse(map->s_type_specific.s_sparing.s_spar_map[i]); +} + static int udf_fill_super(struct super_block *sb, void *options, int silent) { int i; @@ -1846,21 +1868,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) error_out: if (sbi->s_vat_inode) iput(sbi->s_vat_inode); - if (sbi->s_partitions) { - struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) - iput(map->s_uspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) - iput(map->s_fspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) - udf_sb_free_bitmap(map->s_uspace.s_bitmap); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) - udf_sb_free_bitmap(map->s_fspace.s_bitmap); - if (map->s_partition_type == UDF_SPARABLE_MAP15) - for (i = 0; i < 4; i++) - brelse(map->s_type_specific.s_sparing. - s_spar_map[i]); - } + if (sbi->s_partitions) + for (i = 0; i < sbi->s_partitions; i++) + udf_free_partition(&sbi->s_partmaps[i]); #ifdef CONFIG_UDF_NLS if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) unload_nls(sbi->s_nls_map); @@ -1912,21 +1922,9 @@ static void udf_put_super(struct super_block *sb) sbi = UDF_SB(sb); if (sbi->s_vat_inode) iput(sbi->s_vat_inode); - if (sbi->s_partitions) { - struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) - iput(map->s_uspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) - iput(map->s_fspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) - udf_sb_free_bitmap(map->s_uspace.s_bitmap); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) - udf_sb_free_bitmap(map->s_fspace.s_bitmap); - if (map->s_partition_type == UDF_SPARABLE_MAP15) - for (i = 0; i < 4; i++) - brelse(map->s_type_specific.s_sparing. - s_spar_map[i]); - } + if (sbi->s_partitions) + for (i = 0; i < sbi->s_partitions; i++) + udf_free_partition(&sbi->s_partmaps[i]); #ifdef CONFIG_UDF_NLS if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) unload_nls(sbi->s_nls_map); From 3fb38dfa0e28575170119c70cb2ab70fdb8478fb Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 2 Apr 2008 12:26:36 +0200 Subject: [PATCH 28/41] udf: Move filling of partition descriptor info into a separate function Signed-off-by: Jan Kara --- fs/udf/super.c | 198 +++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 96 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index d50e3f5c46e8..c5fef85a9c15 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1024,10 +1024,110 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) return bitmap; } +static int udf_fill_partdesc_info(struct super_block *sb, + struct partitionDesc *p, int p_index) +{ + struct udf_part_map *map; + struct udf_sb_info *sbi = UDF_SB(sb); + struct partitionHeaderDesc *phd; + + map = &sbi->s_partmaps[p_index]; + + map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ + map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); + + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) + map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) + map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) + map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) + map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; + + udf_debug("Partition (%d:%d type %x) starts at physical %d, " + "block length %d\n", partitionNumber, p_index, + map->s_partition_type, map->s_partition_root, + map->s_partition_len); + + if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && + strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) + return 0; + + phd = (struct partitionHeaderDesc *)p->partitionContentsUse; + if (phd->unallocSpaceTable.extLength) { + kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu( + phd->unallocSpaceTable.extPosition), + .partitionReferenceNum = p_index, + }; + + map->s_uspace.s_table = udf_iget(sb, loc); + if (!map->s_uspace.s_table) { + udf_debug("cannot load unallocSpaceTable (part %d)\n", + p_index); + return 1; + } + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; + udf_debug("unallocSpaceTable (part %d) @ %ld\n", + p_index, map->s_uspace.s_table->i_ino); + } + + if (phd->unallocSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); + if (!bitmap) + return 1; + map->s_uspace.s_bitmap = bitmap; + bitmap->s_extLength = le32_to_cpu( + phd->unallocSpaceBitmap.extLength); + bitmap->s_extPosition = le32_to_cpu( + phd->unallocSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; + udf_debug("unallocSpaceBitmap (part %d) @ %d\n", p_index, + bitmap->s_extPosition); + } + + if (phd->partitionIntegrityTable.extLength) + udf_debug("partitionIntegrityTable (part %d)\n", p_index); + + if (phd->freedSpaceTable.extLength) { + kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu( + phd->freedSpaceTable.extPosition), + .partitionReferenceNum = p_index, + }; + + map->s_fspace.s_table = udf_iget(sb, loc); + if (!map->s_fspace.s_table) { + udf_debug("cannot load freedSpaceTable (part %d)\n", + p_index); + return 1; + } + + map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; + udf_debug("freedSpaceTable (part %d) @ %ld\n", + p_index, map->s_fspace.s_table->i_ino); + } + + if (phd->freedSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); + if (!bitmap) + return 1; + map->s_fspace.s_bitmap = bitmap; + bitmap->s_extLength = le32_to_cpu( + phd->freedSpaceBitmap.extLength); + bitmap->s_extPosition = le32_to_cpu( + phd->freedSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; + udf_debug("freedSpaceBitmap (part %d) @ %d\n", p_index, + bitmap->s_extPosition); + } + return 0; +} + static int udf_load_partdesc(struct super_block *sb, sector_t block) { struct buffer_head *bh; - struct partitionHeaderDesc *phd; struct partitionDesc *p; struct udf_part_map *map; struct udf_sb_info *sbi = UDF_SB(sb); @@ -1060,101 +1160,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) goto out_bh; } - map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ - map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); - - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) - map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) - map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) - map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) - map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; - - udf_debug("Partition (%d:%d type %x) starts at physical %d, " - "block length %d\n", partitionNumber, i, - map->s_partition_type, map->s_partition_root, - map->s_partition_len); - - if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && - strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) - goto out_bh; - - phd = (struct partitionHeaderDesc *)p->partitionContentsUse; - if (phd->unallocSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu( - phd->unallocSpaceTable.extPosition), - .partitionReferenceNum = i, - }; - - map->s_uspace.s_table = udf_iget(sb, loc); - if (!map->s_uspace.s_table) { - udf_debug("cannot load unallocSpaceTable (part %d)\n", - i); - ret = 1; - goto out_bh; - } - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; - udf_debug("unallocSpaceTable (part %d) @ %ld\n", - i, map->s_uspace.s_table->i_ino); - } - - if (phd->unallocSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, i); - if (!bitmap) { - ret = 1; - goto out_bh; - } - map->s_uspace.s_bitmap = bitmap; - bitmap->s_extLength = le32_to_cpu( - phd->unallocSpaceBitmap.extLength); - bitmap->s_extPosition = le32_to_cpu( - phd->unallocSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; - udf_debug("unallocSpaceBitmap (part %d) @ %d\n", i, - bitmap->s_extPosition); - } - - if (phd->partitionIntegrityTable.extLength) - udf_debug("partitionIntegrityTable (part %d)\n", i); - - if (phd->freedSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu( - phd->freedSpaceTable.extPosition), - .partitionReferenceNum = i, - }; - - map->s_fspace.s_table = udf_iget(sb, loc); - if (!map->s_fspace.s_table) { - udf_debug("cannot load freedSpaceTable (part %d)\n", i); - ret = 1; - goto out_bh; - } - - map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; - udf_debug("freedSpaceTable (part %d) @ %ld\n", - i, map->s_fspace.s_table->i_ino); - } - - if (phd->freedSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, i); - if (!bitmap) { - ret = 1; - goto out_bh; - } - map->s_fspace.s_bitmap = bitmap; - bitmap->s_extLength = le32_to_cpu( - phd->freedSpaceBitmap.extLength); - bitmap->s_extPosition = le32_to_cpu( - phd->freedSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; - udf_debug("freedSpaceBitmap (part %d) @ %d\n", i, - bitmap->s_extPosition); - } - + ret = udf_fill_partdesc_info(sb, p, i); out_bh: /* In case loading failed, we handle cleanup in udf_fill_super */ brelse(bh); From 38b74a53e5625b7bbbd08918294b86f1db2f0565 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 2 Apr 2008 16:01:35 +0200 Subject: [PATCH 29/41] udf: Move processing of virtual partitions This patch move processing of UDF virtual partitions close to the place where other partition types are processed. As a result we now also properly fill in partition access type. Signed-off-by: Jan Kara --- fs/udf/super.c | 165 +++++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 80 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index c5fef85a9c15..7ec828566df2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -84,7 +84,6 @@ static void udf_write_super(struct super_block *); static int udf_remount_fs(struct super_block *, int *, char *); static int udf_check_valid(struct super_block *, int, int); static int udf_vrs(struct super_block *sb, int silent); -static int udf_load_partition(struct super_block *, kernel_lb_addr *); static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); static void udf_find_anchor(struct super_block *); static int udf_find_fileset(struct super_block *, kernel_lb_addr *, @@ -1125,14 +1124,54 @@ static int udf_fill_partdesc_info(struct super_block *sb, return 0; } +static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_part_map *map = &sbi->s_partmaps[p_index]; + kernel_lb_addr ino; + struct buffer_head *bh; + + /* VAT file entry is in the last recorded block */ + ino.partitionReferenceNum = type1_index; + ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root; + sbi->s_vat_inode = udf_iget(sb, ino); + if (!sbi->s_vat_inode) + return 1; + + if (map->s_partition_type == UDF_VIRTUAL_MAP15) { + map->s_type_specific.s_virtual.s_start_offset = + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - 36) >> 2; + } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { + uint32_t pos; + struct virtualAllocationTable20 *vat20; + + pos = udf_block_map(sbi->s_vat_inode, 0); + bh = sb_bread(sb, pos); + if (!bh) + return 1; + vat20 = (struct virtualAllocationTable20 *)bh->b_data + + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_start_offset = + le16_to_cpu(vat20->lengthHeader) + + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - + map->s_type_specific.s_virtual. + s_start_offset) >> 2; + brelse(bh); + } + return 0; +} + static int udf_load_partdesc(struct super_block *sb, sector_t block) { struct buffer_head *bh; struct partitionDesc *p; struct udf_part_map *map; struct udf_sb_info *sbi = UDF_SB(sb); - bool found = false; - int i; + int i, type1_idx; uint16_t partitionNumber; uint16_t ident; int ret = 0; @@ -1145,22 +1184,59 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) p = (struct partitionDesc *)bh->b_data; partitionNumber = le16_to_cpu(p->partitionNumber); + + /* First scan for TYPE1 and SPARABLE partitions */ for (i = 0; i < sbi->s_partitions; i++) { map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", map->s_partition_num, partitionNumber); - found = map->s_partition_num == partitionNumber; - if (found) + if (map->s_partition_num == partitionNumber && + (map->s_partition_type == UDF_TYPE1_MAP15 || + map->s_partition_type == UDF_SPARABLE_MAP15)) break; } - if (!found) { + if (i >= sbi->s_partitions) { udf_debug("Partition (%d) not found in partition map\n", partitionNumber); goto out_bh; } ret = udf_fill_partdesc_info(sb, p, i); + + /* + * Now rescan for VIRTUAL partitions when TYPE1 partitions are + * already set up + */ + type1_idx = i; + for (i = 0; i < sbi->s_partitions; i++) { + map = &sbi->s_partmaps[i]; + + if (map->s_partition_num == partitionNumber && + (map->s_partition_type == UDF_VIRTUAL_MAP15 || + map->s_partition_type == UDF_VIRTUAL_MAP20)) + break; + } + + if (i >= sbi->s_partitions) + goto out_bh; + + ret = udf_fill_partdesc_info(sb, p, i); + if (ret) + goto out_bh; + + if (!sbi->s_last_block) { + sbi->s_last_block = udf_get_last_block(sb); + udf_find_anchor(sb); + if (!sbi->s_last_block) { + udf_debug("Unable to determine Lastblock (For " + "Virtual Partition)\n"); + ret = 1; + goto out_bh; + } + } + + ret = udf_load_vat(sb, i, type1_idx); out_bh: /* In case loading failed, we handle cleanup in udf_fill_super */ brelse(bh); @@ -1480,13 +1556,13 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) return !block; } -static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) +static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset) { struct anchorVolDescPtr *anchor; uint16_t ident; struct buffer_head *bh; long main_s, main_e, reserve_s, reserve_e; - int i, j; + int i; struct udf_sb_info *sbi; if (!sb) @@ -1535,77 +1611,6 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) } udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); - for (i = 0; i < sbi->s_partitions; i++) { - kernel_lb_addr uninitialized_var(ino); - struct udf_part_map *map = &sbi->s_partmaps[i]; - - if (map->s_partition_type != UDF_VIRTUAL_MAP15 && - map->s_partition_type != UDF_VIRTUAL_MAP20) - continue; - - if (!sbi->s_last_block) { - sbi->s_last_block = udf_get_last_block(sb); - udf_find_anchor(sb); - } - - if (!sbi->s_last_block) { - udf_debug("Unable to determine Lastblock (For " - "Virtual Partition)\n"); - return 1; - } - - for (j = 0; j < sbi->s_partitions; j++) { - struct udf_part_map *map2 = &sbi->s_partmaps[j]; - if (j != i && - map->s_volumeseqnum == - map2->s_volumeseqnum && - map->s_partition_num == - map2->s_partition_num) { - ino.partitionReferenceNum = j; - ino.logicalBlockNum = - sbi->s_last_block - - map2->s_partition_root; - break; - } - } - - if (j == sbi->s_partitions) - return 1; - - sbi->s_vat_inode = udf_iget(sb, ino); - if (!sbi->s_vat_inode) - return 1; - - if (map->s_partition_type == UDF_VIRTUAL_MAP15) { - map->s_type_specific.s_virtual.s_start_offset = - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - 36) >> 2; - } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { - uint32_t pos; - struct virtualAllocationTable20 *vat20; - - pos = udf_block_map(sbi->s_vat_inode, 0); - bh = sb_bread(sb, pos); - if (!bh) - return 1; - vat20 = (struct virtualAllocationTable20 *) - bh->b_data + - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_start_offset = - le16_to_cpu(vat20->lengthHeader) + - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - - map->s_type_specific.s_virtual. - s_start_offset) >> 2; - brelse(bh); - } - map->s_partition_root = udf_get_pblock(sb, 0, i, 0); - map->s_partition_len = - sbi->s_partmaps[ino.partitionReferenceNum]. - s_partition_len; - } return 0; } @@ -1790,7 +1795,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sb->s_magic = UDF_SUPER_MAGIC; sb->s_time_gran = 1000; - if (udf_load_partition(sb, &fileset)) { + if (udf_load_sequence(sb, &fileset)) { printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); goto error_out; } From 423cf6dc04eb79d441bfda2b127bc4b57134b41d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 7 Apr 2008 15:59:23 +0200 Subject: [PATCH 30/41] udf: Cleanup anchor block detection. UDF anchor block detection is complicated by several things - there are several places where the anchor point can be, some of them relative to the last recorded block which some devices report wrongly. Moreover some devices on some media seem to have 7 spare blocks sectors for every 32 blocks (at least as far as I understand the old code) so we have to count also with that possibility. This patch splits anchor block detection into several functions so that it is clearer what we actually try to do. We fix several bugs of the type "for such and such media, we fail to check block blah" as a result of the cleanup. Signed-off-by: Jan Kara --- fs/udf/super.c | 245 ++++++++++++++++++++---------------------------- fs/udf/udf_sb.h | 2 +- 2 files changed, 102 insertions(+), 145 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 7ec828566df2..fe0dafebde71 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -678,149 +678,120 @@ static int udf_vrs(struct super_block *sb, int silent) } /* - * udf_find_anchor + * Check whether there is an anchor block in the given block + */ +static int udf_check_anchor_block(struct super_block *sb, sector_t block, + bool varconv) +{ + struct buffer_head *bh = NULL; + tag *t; + uint16_t ident; + uint32_t location; + + if (varconv) + bh = sb_bread(sb, udf_fixed_to_variable(block)); + else + bh = sb_bread(sb, block); + + if (!bh) + return 0; + + t = (tag *)bh->b_data; + ident = le16_to_cpu(t->tagIdent); + location = le32_to_cpu(t->tagLocation); + brelse(bh); + if (ident != TAG_IDENT_AVDP) + return 0; + return location == block; +} + +/* Search for an anchor volume descriptor pointer */ +static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, + sector_t lastblock) +{ + sector_t last[4]; + int i; + struct udf_sb_info *sbi = UDF_SB(sb); + + last[0] = lastblock; + last[1] = last[0] - 2; + last[2] = last[0] - 150; + last[3] = last[0] - 152; + + /* according to spec, anchor is in either: + * block 256 + * lastblock-256 + * lastblock + * however, if the disc isn't closed, it could be 512 */ + + for (i = 0; i < ARRAY_SIZE(last); i++) { + if (last[i] < 0) + continue; + + if (udf_check_anchor_block(sb, last[i], varconv)) { + sbi->s_anchor[0] = last[i]; + sbi->s_anchor[1] = last[i] - 256; + return last[i]; + } + + if (last[i] < 256) + continue; + + if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { + sbi->s_anchor[1] = last[i] - 256; + return last[i]; + } + } + + if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { + sbi->s_anchor[0] = sbi->s_session + 256; + return last[0]; + } + if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { + sbi->s_anchor[0] = sbi->s_session + 512; + return last[0]; + } + return 0; +} + +/* + * Find an anchor volume descriptor. The function expects sbi->s_lastblock to + * be the last block on the media. * - * PURPOSE - * Find an anchor volume descriptor. + * Return 1 if not found, 0 if ok * - * PRE-CONDITIONS - * sb Pointer to _locked_ superblock. - * lastblock Last block on media. - * - * POST-CONDITIONS - * 1 if not found, 0 if ok - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. */ static void udf_find_anchor(struct super_block *sb) { - int lastblock; + sector_t lastblock; struct buffer_head *bh = NULL; uint16_t ident; - uint32_t location; int i; - struct udf_sb_info *sbi; + struct udf_sb_info *sbi = UDF_SB(sb); - sbi = UDF_SB(sb); - lastblock = sbi->s_last_block; + lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); + if (lastblock) + goto check_anchor; + /* No anchor found? Try VARCONV conversion of block numbers */ + /* Firstly, we try to not convert number of the last block */ + lastblock = udf_scan_anchors(sb, 1, + udf_variable_to_fixed(sbi->s_last_block)); if (lastblock) { - int varlastblock = udf_variable_to_fixed(lastblock); - int last[] = { lastblock, lastblock - 2, - lastblock - 150, lastblock - 152, - varlastblock, varlastblock - 2, - varlastblock - 150, varlastblock - 152 }; - - lastblock = 0; - - /* Search for an anchor volume descriptor pointer */ - - /* according to spec, anchor is in either: - * block 256 - * lastblock-256 - * lastblock - * however, if the disc isn't closed, it could be 512 */ - - for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { - ident = location = 0; - if (last[i] >= 0) { - bh = sb_bread(sb, last[i]); - if (bh) { - tag *t = (tag *)bh->b_data; - ident = le16_to_cpu(t->tagIdent); - location = le32_to_cpu(t->tagLocation); - brelse(bh); - } - } - - if (ident == TAG_IDENT_AVDP) { - if (location == last[i] - sbi->s_session) { - lastblock = last[i] - sbi->s_session; - sbi->s_anchor[0] = lastblock; - sbi->s_anchor[1] = lastblock - 256; - } else if (location == - udf_variable_to_fixed(last[i]) - - sbi->s_session) { - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - lastblock = - udf_variable_to_fixed(last[i]) - - sbi->s_session; - sbi->s_anchor[0] = lastblock; - sbi->s_anchor[1] = lastblock - 256 - - sbi->s_session; - } else { - udf_debug("Anchor found at block %d, " - "location mismatch %d.\n", - last[i], location); - } - } else if (ident == TAG_IDENT_FE || - ident == TAG_IDENT_EFE) { - lastblock = last[i]; - sbi->s_anchor[3] = 512; - } else { - ident = location = 0; - if (last[i] >= 256) { - bh = sb_bread(sb, last[i] - 256); - if (bh) { - tag *t = (tag *)bh->b_data; - ident = le16_to_cpu( - t->tagIdent); - location = le32_to_cpu( - t->tagLocation); - brelse(bh); - } - } - - if (ident == TAG_IDENT_AVDP && - location == last[i] - 256 - - sbi->s_session) { - lastblock = last[i]; - sbi->s_anchor[1] = last[i] - 256; - } else { - ident = location = 0; - if (last[i] >= 312 + sbi->s_session) { - bh = sb_bread(sb, - last[i] - 312 - - sbi->s_session); - if (bh) { - tag *t = (tag *) - bh->b_data; - ident = le16_to_cpu( - t->tagIdent); - location = le32_to_cpu( - t->tagLocation); - brelse(bh); - } - } - - if (ident == TAG_IDENT_AVDP && - location == udf_variable_to_fixed(last[i]) - 256) { - UDF_SET_FLAG(sb, - UDF_FLAG_VARCONV); - lastblock = udf_variable_to_fixed(last[i]); - sbi->s_anchor[1] = lastblock - 256; - } - } - } - } + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); + goto check_anchor; } - if (!lastblock) { - /* We haven't found the lastblock. check 312 */ - bh = sb_bread(sb, 312 + sbi->s_session); - if (bh) { - tag *t = (tag *)bh->b_data; - ident = le16_to_cpu(t->tagIdent); - location = le32_to_cpu(t->tagLocation); - brelse(bh); - - if (ident == TAG_IDENT_AVDP && location == 256) - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - } - } + /* Secondly, we try with converted number of the last block */ + lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); + if (lastblock) + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); +check_anchor: + /* + * Check located anchors and the anchor block supplied via + * mount options + */ for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { if (!sbi->s_anchor[i]) continue; @@ -830,9 +801,7 @@ static void udf_find_anchor(struct super_block *sb) sbi->s_anchor[i] = 0; else { brelse(bh); - if ((ident != TAG_IDENT_AVDP) && - (i || (ident != TAG_IDENT_FE && - ident != TAG_IDENT_EFE))) + if (ident != TAG_IDENT_AVDP) sbi->s_anchor[i] = 0; } } @@ -1225,17 +1194,6 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) if (ret) goto out_bh; - if (!sbi->s_last_block) { - sbi->s_last_block = udf_get_last_block(sb); - udf_find_anchor(sb); - if (!sbi->s_last_block) { - udf_debug("Unable to determine Lastblock (For " - "Virtual Partition)\n"); - ret = 1; - goto out_bh; - } - } - ret = udf_load_vat(sb, i, type1_idx); out_bh: /* In case loading failed, we handle cleanup in udf_fill_super */ @@ -1778,7 +1736,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sbi->s_last_block = uopt.lastblock; sbi->s_anchor[0] = sbi->s_anchor[1] = 0; sbi->s_anchor[2] = uopt.anchor; - sbi->s_anchor[3] = 256; if (udf_check_valid(sb, uopt.novrs, silent)) { /* read volume recognition sequences */ diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index fb2a6e9f8dac..8308a12e1232 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -100,7 +100,7 @@ struct udf_sb_info { /* Sector headers */ __s32 s_session; - __u32 s_anchor[4]; + __u32 s_anchor[3]; __u32 s_last_block; struct buffer_head *s_lvid_bh; From 5fb28aa25ab0b71af2e441d68e63ad257e610a04 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 7 Apr 2008 16:15:04 +0200 Subject: [PATCH 31/41] udf: Improve anchor block detection Add +1 and -1 to a list of blocks which can be the real last recorded block on a UDF media. Sebastian Manciulea claims this helps some drive + media combinations he is able to test. Signed-off-by: Jan Kara --- fs/udf/super.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index fe0dafebde71..b9e719de0704 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -709,14 +709,16 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, sector_t lastblock) { - sector_t last[4]; + sector_t last[6]; int i; struct udf_sb_info *sbi = UDF_SB(sb); last[0] = lastblock; - last[1] = last[0] - 2; - last[2] = last[0] - 150; - last[3] = last[0] - 152; + last[1] = last[0] - 1; + last[2] = last[0] + 1; + last[3] = last[0] - 2; + last[4] = last[0] - 150; + last[5] = last[0] - 152; /* according to spec, anchor is in either: * block 256 @@ -727,6 +729,9 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, for (i = 0; i < ARRAY_SIZE(last); i++) { if (last[i] < 0) continue; + if (last[i] >= sb->s_bdev->bd_inode->i_size >> + sb->s_blocksize_bits) + continue; if (udf_check_anchor_block(sb, last[i], varconv)) { sbi->s_anchor[0] = last[i]; From 4f7874c868eaedd0e64b2f6c800bc852bdc7f38b Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 7 Apr 2008 23:16:38 +0200 Subject: [PATCH 32/41] udf: Silence warning about accesses beyond end of device Some of the computed positions of anchor block could be beyond the end of device. Skip reading such blocks. Signed-off-by: Jan Kara --- fs/udf/super.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index b9e719de0704..28ed3f5ebd70 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -688,8 +688,12 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, uint16_t ident; uint32_t location; - if (varconv) + if (varconv) { + if (udf_fixed_to_variable(block) >= + sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) + return 0; bh = sb_bread(sb, udf_fixed_to_variable(block)); + } else bh = sb_bread(sb, block); From c82a127505d39fa81c886eceed6fdf8c1ff4a06b Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 Apr 2008 01:16:32 +0200 Subject: [PATCH 33/41] udf: Fix detection of VAT version We incorrectly (way to strictly) checked version of VAT on loading and thus refuse to mount correct media. There are just two format versions - below 2.0 and above 2.0 and we understand both. So update the version check accordingly. Signed-off-by: Jan Kara --- fs/udf/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 28ed3f5ebd70..14f965e8a738 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1256,12 +1256,12 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, u16 suf = le16_to_cpu(((__le16 *)upm2->partIdent. identSuffix)[0]); - if (suf == 0x0150) { + if (suf < 0x0200) { map->s_partition_type = UDF_VIRTUAL_MAP15; map->s_partition_func = udf_get_pblock_virt15; - } else if (suf == 0x0200) { + } else { map->s_partition_type = UDF_VIRTUAL_MAP20; map->s_partition_func = From 742e1795e2d9dc99657742e5bbbb7907596bf6c3 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 Apr 2008 01:17:52 +0200 Subject: [PATCH 34/41] udf: Allow loading of VAT inode UDF media with VAT could have never worked because udf_fill_inode() didn't know about case FILE_TYPE_VAT20. Fix this. Signed-off-by: Jan Kara --- fs/udf/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 2362bf0c6900..c150b6df6261 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1275,6 +1275,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) case ICBTAG_FILE_TYPE_REALTIME: case ICBTAG_FILE_TYPE_REGULAR: case ICBTAG_FILE_TYPE_UNDEF: + case ICBTAG_FILE_TYPE_VAT20: if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) inode->i_data.a_ops = &udf_adinicb_aops; else From fa5e08156335d0687c85b4e724db9448fb166601 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 Apr 2008 02:08:53 +0200 Subject: [PATCH 35/41] udf: Handle VAT packed inside inode properly We didn't handle VAT packed inside the inode - we tried to call udf_block_map() on such file which lead to strange results at best. Add proper handling of packed VAT as we do it with other packed files. Signed-off-by: Jan Kara --- fs/udf/partition.c | 10 +++++++--- fs/udf/super.c | 24 +++++++++++++++--------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/fs/udf/partition.c b/fs/udf/partition.c index 307c9c33d184..b2e6e1eddb90 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -54,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, struct udf_sb_info *sbi = UDF_SB(sb); struct udf_part_map *map; struct udf_virtual_data *vdata; - struct udf_inode_info *iinfo; + struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode); map = &sbi->s_partmaps[partition]; vdata = &map->s_type_specific.s_virtual; - index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); if (block > vdata->s_num_entries) { udf_debug("Trying to access block beyond end of VAT " @@ -66,6 +65,11 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, return 0xFFFFFFFF; } + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { + loc = le32_to_cpu(((__le32 *)iinfo->i_ext.i_data)[block]); + goto translate; + } + index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); if (block >= index) { block -= index; newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); @@ -88,7 +92,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, brelse(bh); - iinfo = UDF_I(sbi->s_vat_inode); +translate: if (iinfo->i_location.partitionReferenceNum == partition) { udf_debug("recursive call to udf_get_pblock!\n"); return 0xFFFFFFFF; diff --git a/fs/udf/super.c b/fs/udf/super.c index 14f965e8a738..abdb9b31da46 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1107,7 +1107,10 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) struct udf_sb_info *sbi = UDF_SB(sb); struct udf_part_map *map = &sbi->s_partmaps[p_index]; kernel_lb_addr ino; - struct buffer_head *bh; + struct buffer_head *bh = NULL; + struct udf_inode_info *vati; + uint32_t pos; + struct virtualAllocationTable20 *vat20; /* VAT file entry is in the last recorded block */ ino.partitionReferenceNum = type1_index; @@ -1122,15 +1125,18 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) map->s_type_specific.s_virtual.s_num_entries = (sbi->s_vat_inode->i_size - 36) >> 2; } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { - uint32_t pos; - struct virtualAllocationTable20 *vat20; + vati = UDF_I(sbi->s_vat_inode); + if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + pos = udf_block_map(sbi->s_vat_inode, 0); + bh = sb_bread(sb, pos); + if (!bh) + return 1; + vat20 = (struct virtualAllocationTable20 *)bh->b_data; + } else { + vat20 = (struct virtualAllocationTable20 *) + vati->i_ext.i_data; + } - pos = udf_block_map(sbi->s_vat_inode, 0); - bh = sb_bread(sb, pos); - if (!bh) - return 1; - vat20 = (struct virtualAllocationTable20 *)bh->b_data + - udf_ext0_offset(sbi->s_vat_inode); map->s_type_specific.s_virtual.s_start_offset = le16_to_cpu(vat20->lengthHeader) + udf_ext0_offset(sbi->s_vat_inode); From 96200be3077c5ede16a90b33aca815b444e66043 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 Apr 2008 13:29:20 +0200 Subject: [PATCH 36/41] udf: Mount filesystem read-only if it has pseudooverwrite partition As we don't properly support writing to pseudooverwrite partition (we should add entries to VAT and relocate blocks instead of just writing them), mount filesystems with such partition as read-only. Signed-off-by: Jan Kara --- fs/udf/super.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/udf/super.c b/fs/udf/super.c index abdb9b31da46..650f20fe9d62 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1208,6 +1208,14 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ret = udf_fill_partdesc_info(sb, p, i); if (ret) goto out_bh; + /* + * Mark filesystem read-only if we have a partition with virtual map + * since we don't handle writing to it (we overwrite blocks instead of + * relocating them). + */ + sb->s_flags |= MS_RDONLY; + printk(KERN_NOTICE "UDF-fs: Filesystem marked read-only because " + "writing to pseudooverwrite partition is not implemented.\n"); ret = udf_load_vat(sb, i, type1_idx); out_bh: From f4bcbbd92ebda971f7c2cd1132b399808ed6cf9b Mon Sep 17 00:00:00 2001 From: Sebastian Manciulea Date: Tue, 8 Apr 2008 14:02:11 +0200 Subject: [PATCH 37/41] udf: Fix handling of multisession media According to OSTA UDF specification, only anchor blocks and primary volume descriptors are placed on media relative to the last session. All other block numbers are absolute (in the partition or the whole media). This seems to be confirmed by multisession media created by other systems. Signed-off-by: Sebastian Manciulea Signed-off-by: Jan Kara --- fs/udf/misc.c | 13 +++++-------- fs/udf/super.c | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fs/udf/misc.c b/fs/udf/misc.c index 581b6e4cc591..96996204d928 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -203,16 +203,15 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, { tag *tag_p; struct buffer_head *bh = NULL; - struct udf_sb_info *sbi = UDF_SB(sb); /* Read the block */ if (block == 0xFFFFFFFF) return NULL; - bh = udf_tread(sb, block + sbi->s_session); + bh = udf_tread(sb, block); if (!bh) { udf_debug("block=%d, location=%d: read failed\n", - block + sbi->s_session, location); + block, location); return NULL; } @@ -222,8 +221,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, if (location != le32_to_cpu(tag_p->tagLocation)) { udf_debug("location mismatch block %u, tag %u != %u\n", - block + sbi->s_session, - le32_to_cpu(tag_p->tagLocation), location); + block, le32_to_cpu(tag_p->tagLocation), location); goto error_out; } @@ -247,9 +245,8 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, le16_to_cpu(tag_p->descCRCLength), 0)) return bh; - udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", - block + sbi->s_session, le16_to_cpu(tag_p->descCRC), - le16_to_cpu(tag_p->descCRCLength)); + udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block, + le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); error_out: brelse(bh); diff --git a/fs/udf/super.c b/fs/udf/super.c index 650f20fe9d62..787cedf6cc07 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -587,7 +587,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) static int udf_vrs(struct super_block *sb, int silent) { struct volStructDesc *vsd = NULL; - int sector = 32768; + loff_t sector = 32768; int sectorsize; struct buffer_head *bh = NULL; int iso9660 = 0; From bfb257a5981af805a9394f00f75d3d9f7b611cc0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 8 Apr 2008 20:37:21 +0200 Subject: [PATCH 38/41] udf: Add read-only support for 2.50 UDF media This patch implements parsing of metadata partitions and reading of Metadata File thus allowing to read UDF 2.50 media. Error resilience is implemented through accessing the Metadata Mirror File in case the data the Metadata File cannot be read. The patch is based on the original patch by Sebastian Manciulea and Mircea Fedoreanu . Signed-off-by: Sebastian Manciulea Signed-off-by: Mircea Fedoreanu Signed-off-by: Jan Kara --- fs/udf/inode.c | 9 +++ fs/udf/partition.c | 55 +++++++++++++ fs/udf/super.c | 190 +++++++++++++++++++++++++++++++++++++++++---- fs/udf/udf_sb.h | 16 +++- fs/udf/udfdecl.h | 2 + 5 files changed, 258 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index c150b6df6261..6e151f170c08 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1301,6 +1301,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_op = &page_symlink_inode_operations; inode->i_mode = S_IFLNK | S_IRWXUGO; break; + case ICBTAG_FILE_TYPE_MAIN: + udf_debug("METADATA FILE-----\n"); + break; + case ICBTAG_FILE_TYPE_MIRROR: + udf_debug("METADATA MIRROR FILE-----\n"); + break; + case ICBTAG_FILE_TYPE_BITMAP: + udf_debug("METADATA BITMAP FILE-----\n"); + break; default: printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown " "file type=%d\n", inode->i_ino, diff --git a/fs/udf/partition.c b/fs/udf/partition.c index b2e6e1eddb90..2dfe4be2eeb2 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -266,3 +266,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) return 0; } + +static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, + uint16_t partition, uint32_t offset) +{ + struct super_block *sb = inode->i_sb; + struct udf_part_map *map; + kernel_lb_addr eloc; + uint32_t elen; + sector_t ext_offset; + struct extent_position epos = {}; + uint32_t phyblock; + + if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != + (EXT_RECORDED_ALLOCATED >> 30)) + phyblock = 0xFFFFFFFF; + else { + map = &UDF_SB(sb)->s_partmaps[partition]; + /* map to sparable/physical partition desc */ + phyblock = udf_get_pblock(sb, eloc.logicalBlockNum, + map->s_partition_num, ext_offset + offset); + } + + brelse(epos.bh); + return phyblock; +} + +uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block, + uint16_t partition, uint32_t offset) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_part_map *map; + struct udf_meta_data *mdata; + uint32_t retblk; + struct inode *inode; + + udf_debug("READING from METADATA\n"); + + map = &sbi->s_partmaps[partition]; + mdata = &map->s_type_specific.s_metadata; + inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe; + + /* We shouldn't mount such media... */ + BUG_ON(!inode); + retblk = udf_try_read_meta(inode, block, partition, offset); + if (retblk == 0xFFFFFFFF) { + udf_warning(sb, __func__, "error reading from METADATA, " + "trying to read from MIRROR"); + inode = mdata->s_mirror_fe; + if (!inode) + return 0xFFFFFFFF; + retblk = udf_try_read_meta(inode, block, partition, offset); + } + + return retblk; +} diff --git a/fs/udf/super.c b/fs/udf/super.c index 787cedf6cc07..29b19678327a 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -950,6 +950,101 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) return 0; } +static int udf_load_metadata_files(struct super_block *sb, int partition) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_part_map *map; + struct udf_meta_data *mdata; + kernel_lb_addr addr; + int fe_error = 0; + + map = &sbi->s_partmaps[partition]; + mdata = &map->s_type_specific.s_metadata; + + /* metadata address */ + addr.logicalBlockNum = mdata->s_meta_file_loc; + addr.partitionReferenceNum = map->s_partition_num; + + udf_debug("Metadata file location: block = %d part = %d\n", + addr.logicalBlockNum, addr.partitionReferenceNum); + + mdata->s_metadata_fe = udf_iget(sb, addr); + + if (mdata->s_metadata_fe == NULL) { + udf_warning(sb, __func__, "metadata inode efe not found, " + "will try mirror inode."); + fe_error = 1; + } else if (UDF_I(mdata->s_metadata_fe)->i_alloc_type != + ICBTAG_FLAG_AD_SHORT) { + udf_warning(sb, __func__, "metadata inode efe does not have " + "short allocation descriptors!"); + fe_error = 1; + iput(mdata->s_metadata_fe); + mdata->s_metadata_fe = NULL; + } + + /* mirror file entry */ + addr.logicalBlockNum = mdata->s_mirror_file_loc; + addr.partitionReferenceNum = map->s_partition_num; + + udf_debug("Mirror metadata file location: block = %d part = %d\n", + addr.logicalBlockNum, addr.partitionReferenceNum); + + mdata->s_mirror_fe = udf_iget(sb, addr); + + if (mdata->s_mirror_fe == NULL) { + if (fe_error) { + udf_error(sb, __func__, "mirror inode efe not found " + "and metadata inode is missing too, exiting..."); + goto error_exit; + } else + udf_warning(sb, __func__, "mirror inode efe not found," + " but metadata inode is OK"); + } else if (UDF_I(mdata->s_mirror_fe)->i_alloc_type != + ICBTAG_FLAG_AD_SHORT) { + udf_warning(sb, __func__, "mirror inode efe does not have " + "short allocation descriptors!"); + iput(mdata->s_mirror_fe); + mdata->s_mirror_fe = NULL; + if (fe_error) + goto error_exit; + } + + /* + * bitmap file entry + * Note: + * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102) + */ + if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) { + addr.logicalBlockNum = mdata->s_bitmap_file_loc; + addr.partitionReferenceNum = map->s_partition_num; + + udf_debug("Bitmap file location: block = %d part = %d\n", + addr.logicalBlockNum, addr.partitionReferenceNum); + + mdata->s_bitmap_fe = udf_iget(sb, addr); + + if (mdata->s_bitmap_fe == NULL) { + if (sb->s_flags & MS_RDONLY) + udf_warning(sb, __func__, "bitmap inode efe " + "not found but it's ok since the disc" + " is mounted read-only"); + else { + udf_error(sb, __func__, "bitmap inode efe not " + "found and attempted read-write mount"); + goto error_exit; + } + } + } + + udf_debug("udf_load_metadata_files Ok\n"); + + return 0; + +error_exit: + return 1; +} + static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr *root) { @@ -1169,7 +1264,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) p = (struct partitionDesc *)bh->b_data; partitionNumber = le16_to_cpu(p->partitionNumber); - /* First scan for TYPE1 and SPARABLE partitions */ + /* First scan for TYPE1, SPARABLE and METADATA partitions */ for (i = 0; i < sbi->s_partitions; i++) { map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", @@ -1189,8 +1284,8 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ret = udf_fill_partdesc_info(sb, p, i); /* - * Now rescan for VIRTUAL partitions when TYPE1 partitions are - * already set up + * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and + * PHYSICAL partitions are already set up */ type1_idx = i; for (i = 0; i < sbi->s_partitions; i++) { @@ -1198,7 +1293,8 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) if (map->s_partition_num == partitionNumber && (map->s_partition_type == UDF_VIRTUAL_MAP15 || - map->s_partition_type == UDF_VIRTUAL_MAP20)) + map->s_partition_type == UDF_VIRTUAL_MAP20 || + map->s_partition_type == UDF_METADATA_MAP25)) break; } @@ -1208,16 +1304,28 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ret = udf_fill_partdesc_info(sb, p, i); if (ret) goto out_bh; - /* - * Mark filesystem read-only if we have a partition with virtual map - * since we don't handle writing to it (we overwrite blocks instead of - * relocating them). - */ - sb->s_flags |= MS_RDONLY; - printk(KERN_NOTICE "UDF-fs: Filesystem marked read-only because " - "writing to pseudooverwrite partition is not implemented.\n"); - ret = udf_load_vat(sb, i, type1_idx); + if (map->s_partition_type == UDF_METADATA_MAP25) { + ret = udf_load_metadata_files(sb, i); + if (ret) { + printk(KERN_ERR "UDF-fs: error loading MetaData " + "partition map %d\n", i); + goto out_bh; + } + } else { + ret = udf_load_vat(sb, i, type1_idx); + if (ret) + goto out_bh; + /* + * Mark filesystem read-only if we have a partition with + * virtual map since we don't handle writing to it (we + * overwrite blocks instead of relocating them). + */ + sb->s_flags |= MS_RDONLY; + printk(KERN_NOTICE "UDF-fs: Filesystem marked read-only " + "because writing to pseudooverwrite partition is " + "not implemented.\n"); + } out_bh: /* In case loading failed, we handle cleanup in udf_fill_super */ brelse(bh); @@ -1316,6 +1424,50 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, } } map->s_partition_func = udf_get_pblock_spar15; + } else if (!strncmp(upm2->partIdent.ident, + UDF_ID_METADATA, + strlen(UDF_ID_METADATA))) { + struct udf_meta_data *mdata = + &map->s_type_specific.s_metadata; + struct metadataPartitionMap *mdm = + (struct metadataPartitionMap *) + &(lvd->partitionMaps[offset]); + udf_debug("Parsing Logical vol part %d " + "type %d id=%s\n", i, type, + UDF_ID_METADATA); + + map->s_partition_type = UDF_METADATA_MAP25; + map->s_partition_func = udf_get_pblock_meta25; + + mdata->s_meta_file_loc = + le32_to_cpu(mdm->metadataFileLoc); + mdata->s_mirror_file_loc = + le32_to_cpu(mdm->metadataMirrorFileLoc); + mdata->s_bitmap_file_loc = + le32_to_cpu(mdm->metadataBitmapFileLoc); + mdata->s_alloc_unit_size = + le32_to_cpu(mdm->allocUnitSize); + mdata->s_align_unit_size = + le16_to_cpu(mdm->alignUnitSize); + mdata->s_dup_md_flag = + mdm->flags & 0x01; + + udf_debug("Metadata Ident suffix=0x%x\n", + (le16_to_cpu( + ((__le16 *) + mdm->partIdent.identSuffix)[0]))); + udf_debug("Metadata part num=%d\n", + le16_to_cpu(mdm->partitionNum)); + udf_debug("Metadata part alloc unit size=%d\n", + le32_to_cpu(mdm->allocUnitSize)); + udf_debug("Metadata file loc=%d\n", + le32_to_cpu(mdm->metadataFileLoc)); + udf_debug("Mirror file loc=%d\n", + le32_to_cpu(mdm->metadataMirrorFileLoc)); + udf_debug("Bitmap file loc=%d\n", + le32_to_cpu(mdm->metadataBitmapFileLoc)); + udf_debug("Duplicate Flag: %d %d\n", + mdata->s_dup_md_flag, mdm->flags); } else { udf_debug("Unknown ident: %s\n", upm2->partIdent.ident); @@ -1677,6 +1829,7 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) static void udf_free_partition(struct udf_part_map *map) { int i; + struct udf_meta_data *mdata; if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) iput(map->s_uspace.s_table); @@ -1689,6 +1842,17 @@ static void udf_free_partition(struct udf_part_map *map) if (map->s_partition_type == UDF_SPARABLE_MAP15) for (i = 0; i < 4; i++) brelse(map->s_type_specific.s_sparing.s_spar_map[i]); + else if (map->s_partition_type == UDF_METADATA_MAP25) { + mdata = &map->s_type_specific.s_metadata; + iput(mdata->s_metadata_fe); + mdata->s_metadata_fe = NULL; + + iput(mdata->s_mirror_fe); + mdata->s_mirror_fe = NULL; + + iput(mdata->s_bitmap_fe); + mdata->s_bitmap_fe = NULL; + } } static int udf_fill_super(struct super_block *sb, void *options, int silent) diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 8308a12e1232..1c1c514a9725 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -6,7 +6,7 @@ /* Since UDF 2.01 is ISO 13346 based... */ #define UDF_SUPER_MAGIC 0x15013346 -#define UDF_MAX_READ_VERSION 0x0201 +#define UDF_MAX_READ_VERSION 0x0250 #define UDF_MAX_WRITE_VERSION 0x0201 #define UDF_FLAG_USE_EXTENDED_FE 0 @@ -46,9 +46,22 @@ #define UDF_VIRTUAL_MAP15 0x1512U #define UDF_VIRTUAL_MAP20 0x2012U #define UDF_SPARABLE_MAP15 0x1522U +#define UDF_METADATA_MAP25 0x2511U #pragma pack(1) /* XXX(hch): Why? This file just defines in-core structures */ +struct udf_meta_data { + __u32 s_meta_file_loc; + __u32 s_mirror_file_loc; + __u32 s_bitmap_file_loc; + __u32 s_alloc_unit_size; + __u16 s_align_unit_size; + __u8 s_dup_md_flag; + struct inode *s_metadata_fe; + struct inode *s_mirror_fe; + struct inode *s_bitmap_fe; +}; + struct udf_sparing_data { __u16 s_packet_len; struct buffer_head *s_spar_map[4]; @@ -82,6 +95,7 @@ struct udf_part_map { union { struct udf_sparing_data s_sparing; struct udf_virtual_data s_virtual; + struct udf_meta_data s_metadata; } s_type_specific; __u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32); __u16 s_volumeseqnum; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 2cb2f5de4245..30f664ab0cd9 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -177,6 +177,8 @@ extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, uint32_t); extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, uint32_t); +extern uint32_t udf_get_pblock_meta25(struct super_block *, uint32_t, uint16_t, + uint32_t); extern int udf_relocate_blocks(struct super_block *, long, long *); /* unicode.c */ From 47c9358a015199ed37c66235a2238271a7c8041f Mon Sep 17 00:00:00 2001 From: Sebastian Manciulea Date: Mon, 14 Apr 2008 17:06:36 +0200 Subject: [PATCH 39/41] udf: Fix bug in VAT mapping code Fix mapping of blocks using VAT when it is stored in an inode. UDF_I(inode)->i_data already points to the beginning of VAT header so there's no need to add udf_ext0_offset(inode). Signed-off-by: Sebastian Manciulea Signed-off-by: Jan Kara --- fs/udf/partition.c | 3 ++- fs/udf/super.c | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/udf/partition.c b/fs/udf/partition.c index 2dfe4be2eeb2..63610f026ae1 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -66,7 +66,8 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, } if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { - loc = le32_to_cpu(((__le32 *)iinfo->i_ext.i_data)[block]); + loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data + + vdata->s_start_offset))[block]); goto translate; } index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); diff --git a/fs/udf/super.c b/fs/udf/super.c index 29b19678327a..8f02b30c22ef 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1215,8 +1215,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) return 1; if (map->s_partition_type == UDF_VIRTUAL_MAP15) { - map->s_type_specific.s_virtual.s_start_offset = - udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_start_offset = 0; map->s_type_specific.s_virtual.s_num_entries = (sbi->s_vat_inode->i_size - 36) >> 2; } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { @@ -1233,8 +1232,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) } map->s_type_specific.s_virtual.s_start_offset = - le16_to_cpu(vat20->lengthHeader) + - udf_ext0_offset(sbi->s_vat_inode); + le16_to_cpu(vat20->lengthHeader); map->s_type_specific.s_virtual.s_num_entries = (sbi->s_vat_inode->i_size - map->s_type_specific.s_virtual. From 706047a79725b585cf272fdefc234b31b6545c72 Mon Sep 17 00:00:00 2001 From: Sebastian Manciulea Date: Mon, 14 Apr 2008 17:13:01 +0200 Subject: [PATCH 40/41] udf: Fix compilation warnings when UDF debug is on Fix two compilation warnings (and actual bugs in message formatting) when UDF debugging is turned on. Signed-off-by: Sebastian Manciulea Signed-off-by: Jan Kara --- fs/udf/super.c | 7 ++++--- fs/udf/udfdecl.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 8f02b30c22ef..6823733c0121 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -608,7 +608,8 @@ static int udf_vrs(struct super_block *sb, int silent) sector += (sbi->s_session << sb->s_blocksize_bits); udf_debug("Starting at sector %u (%ld byte sectors)\n", - (sector >> sb->s_blocksize_bits), sb->s_blocksize); + (unsigned int)(sector >> sb->s_blocksize_bits), + sb->s_blocksize); /* Process the sequence (if applicable) */ for (; !nsr02 && !nsr03; sector += sectorsize) { /* Read a block */ @@ -1117,8 +1118,8 @@ static int udf_fill_partdesc_info(struct super_block *sb, if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; - udf_debug("Partition (%d:%d type %x) starts at physical %d, " - "block length %d\n", partitionNumber, p_index, + udf_debug("Partition (%d type %x) starts at physical %d, " + "block length %d\n", p_index, map->s_partition_type, map->s_partition_root, map->s_partition_len); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 30f664ab0cd9..61897d312a2e 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -16,7 +16,7 @@ #define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 -#undef UDFFS_DEBUG +#define UDFFS_DEBUG #ifdef UDFFS_DEBUG #define udf_debug(f, a...) \ From f845fced913b1437659bb5baf187698547697afe Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 17 Apr 2008 09:47:48 +0200 Subject: [PATCH 41/41] udf: use crc_itu_t from lib instead of udf_crc As pointed out by Sergey Vlasov, UDF implements its own version of the CRC ITU-T V.41. Convert it to use the one in the library. Signed-off-by: Bob Copeland Cc: Sergey Vlasov Signed-off-by: Jan Kara --- fs/Kconfig | 1 + fs/udf/Makefile | 2 +- fs/udf/crc.c | 172 ----------------------------------------------- fs/udf/inode.c | 11 +-- fs/udf/misc.c | 12 ++-- fs/udf/namei.c | 21 +++--- fs/udf/super.c | 10 +-- fs/udf/udfdecl.h | 3 - fs/udf/unicode.c | 3 +- 9 files changed, 32 insertions(+), 203 deletions(-) delete mode 100644 fs/udf/crc.c diff --git a/fs/Kconfig b/fs/Kconfig index d7312825592b..86229c913ace 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -663,6 +663,7 @@ config ZISOFS config UDF_FS tristate "UDF file system support" + select CRC_ITU_T help This is the new file system used on some CD-ROMs and DVDs. Say Y if you intend to mount DVD discs or CDRW's written in packet mode, or diff --git a/fs/udf/Makefile b/fs/udf/Makefile index be845e7540ef..0d4503f7446d 100644 --- a/fs/udf/Makefile +++ b/fs/udf/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_UDF_FS) += udf.o udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ partition.o super.o truncate.o symlink.o fsync.o \ - crc.o directory.o misc.o udftime.o unicode.o + directory.o misc.o udftime.o unicode.o diff --git a/fs/udf/crc.c b/fs/udf/crc.c deleted file mode 100644 index f178c63686e0..000000000000 --- a/fs/udf/crc.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * crc.c - * - * PURPOSE - * Routines to generate, calculate, and test a 16-bit CRC. - * - * DESCRIPTION - * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories - * and Ned W. Rhodes of Software Systems Group. It has been published in - * "Design and Validation of Computer Protocols", Prentice Hall, - * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4. - * - * Copyright is held by AT&T. - * - * AT&T gives permission for the free use of the CRC source code. - * - * COPYRIGHT - * This file is distributed under the terms of the GNU General Public - * License (GPL). Copies of the GPL can be obtained from: - * ftp://prep.ai.mit.edu/pub/gnu/GPL - * Each contributing author retains all rights to their own work. - */ - -#include "udfdecl.h" - -static const uint16_t crc_table[256] = { - 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, - 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, - 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, - 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, - 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, - 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, - 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, - 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, - 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, - 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, - 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, - 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, - 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, - 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, - 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, - 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, - 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, - 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, - 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, - 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, - 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, - 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, - 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, - 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, - 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, - 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, - 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, - 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, - 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, - 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, - 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, - 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U -}; - -/* - * udf_crc - * - * PURPOSE - * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. - * - * DESCRIPTION - * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. - * The polynomial used is: x^16 + x^12 + x^15 + 1 - * - * PRE-CONDITIONS - * data Pointer to the data block. - * size Size of the data block. - * - * POST-CONDITIONS - * CRC of the data block. - * - * HISTORY - * July 21, 1997 - Andrew E. Mileski - * Adapted from OSTA-UDF(tm) 1.50 standard. - */ -uint16_t udf_crc(const uint8_t *data, uint32_t size, uint16_t crc) -{ - while (size--) - crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); - - return crc; -} - -/****************************************************************************/ -#if defined(TEST) - -/* - * PURPOSE - * Test udf_crc() - * - * HISTORY - * July 21, 1997 - Andrew E. Mileski - * Adapted from OSTA-UDF(tm) 1.50 standard. - */ - -unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U }; - -int main(void) -{ - unsigned short x; - - x = udf_crc(bytes, sizeof bytes); - printf("udf_crc: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U); - - return 0; -} - -#endif /* defined(TEST) */ - -/****************************************************************************/ -#if defined(GENERATE) - -/* - * PURPOSE - * Generate a table for fast 16-bit CRC calculations (any polynomial). - * - * DESCRIPTION - * The ITU-T V.41 polynomial is 010041. - * - * HISTORY - * July 21, 1997 - Andrew E. Mileski - * Adapted from OSTA-UDF(tm) 1.50 standard. - */ - -#include - -int main(int argc, char **argv) -{ - unsigned long crc, poly; - int n, i; - - /* Get the polynomial */ - sscanf(argv[1], "%lo", &poly); - if (poly & 0xffff0000U) { - fprintf(stderr, "polynomial is too large\en"); - exit(1); - } - - printf("/* CRC 0%o */\n", poly); - - /* Create a table */ - printf("static unsigned short crc_table[256] = {\n"); - for (n = 0; n < 256; n++) { - if (n % 8 == 0) - printf("\t"); - crc = n << 8; - for (i = 0; i < 8; i++) { - if (crc & 0x8000U) - crc = (crc << 1) ^ poly; - else - crc <<= 1; - crc &= 0xFFFFU; - } - if (n == 255) - printf("0x%04xU ", crc); - else - printf("0x%04xU, ", crc); - if (n % 8 == 7) - printf("\n"); - } - printf("};\n"); - - return 0; -} - -#endif /* defined(GENERATE) */ diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 6e151f170c08..6e74b117aaf0 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "udf_i.h" #include "udf_sb.h" @@ -1419,9 +1420,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) iinfo->i_location. logicalBlockNum); use->descTag.descCRCLength = cpu_to_le16(crclen); - use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + - sizeof(tag), crclen, - 0)); + use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + + sizeof(tag), + crclen)); use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); mark_buffer_dirty(bh); @@ -1584,8 +1585,8 @@ static int udf_update_inode(struct inode *inode, int do_sync) crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - sizeof(tag); fe->descTag.descCRCLength = cpu_to_le16(crclen); - fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), - crclen, 0)); + fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(tag), + crclen)); fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); /* write the data blocks */ diff --git a/fs/udf/misc.c b/fs/udf/misc.c index 96996204d928..84bf0fd4a4f1 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "udf_i.h" #include "udf_sb.h" @@ -135,8 +136,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, /* rewrite CRC + checksum of eahd */ crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); eahd->descTag.descCRCLength = cpu_to_le16(crclen); - eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + - sizeof(tag), crclen, 0)); + eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd + + sizeof(tag), crclen)); eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag); iinfo->i_lenEAttr += size; return (struct genericFormat *)&ea[offset]; @@ -241,8 +242,9 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, /* Verify the descriptor CRC */ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || - le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), - le16_to_cpu(tag_p->descCRCLength), 0)) + le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, + bh->b_data + sizeof(tag), + le16_to_cpu(tag_p->descCRCLength))) return bh; udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block, @@ -266,7 +268,7 @@ void udf_update_tag(char *data, int length) length -= sizeof(tag); tptr->descCRCLength = cpu_to_le16(length); - tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0)); + tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(tag), length)); tptr->tagChecksum = udf_tag_checksum(tptr); } diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 68686b79650a..ba5537d4bc15 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -31,6 +31,7 @@ #include #include #include +#include static inline int udf_match(int len1, const char *name1, int len2, const char *name2) @@ -97,25 +98,23 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, memset(fibh->ebh->b_data, 0x00, padlen + offset); } - crc = udf_crc((uint8_t *)cfi + sizeof(tag), - sizeof(struct fileIdentDesc) - sizeof(tag), 0); + crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag), + sizeof(struct fileIdentDesc) - sizeof(tag)); if (fibh->sbh == fibh->ebh) { - crc = udf_crc((uint8_t *)sfi->impUse, + crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, crclen + sizeof(tag) - - sizeof(struct fileIdentDesc), crc); + sizeof(struct fileIdentDesc)); } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) { - crc = udf_crc(fibh->ebh->b_data + + crc = crc_itu_t(crc, fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset, crclen + sizeof(tag) - - sizeof(struct fileIdentDesc), - crc); + sizeof(struct fileIdentDesc)); } else { - crc = udf_crc((uint8_t *)sfi->impUse, - -fibh->soffset - sizeof(struct fileIdentDesc), - crc); - crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc); + crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, + -fibh->soffset - sizeof(struct fileIdentDesc)); + crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset); } cfi->descTag.descCRC = cpu_to_le16(crc); diff --git a/fs/udf/super.c b/fs/udf/super.c index 6823733c0121..b564fc140fe4 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include "udf_sb.h" @@ -1765,8 +1766,8 @@ static void udf_open_lvid(struct super_block *sb) lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; lvid->descTag.descCRC = cpu_to_le16( - udf_crc((char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength), 0)); + crc_itu_t(0, (char *)lvid + sizeof(tag), + le16_to_cpu(lvid->descTag.descCRCLength))); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); mark_buffer_dirty(bh); @@ -1800,9 +1801,8 @@ static void udf_close_lvid(struct super_block *sb) lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); lvid->descTag.descCRC = cpu_to_le16( - udf_crc((char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength), - 0)); + crc_itu_t(0, (char *)lvid + sizeof(tag), + le16_to_cpu(lvid->descTag.descCRCLength))); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); mark_buffer_dirty(bh); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 61897d312a2e..f3f45d029277 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -220,9 +220,6 @@ extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); -/* crc.c */ -extern uint16_t udf_crc(const uint8_t *, uint32_t, uint16_t); - /* udftime.c */ extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src); diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index f5872ae325a3..9fdf8c93c58e 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -23,6 +23,7 @@ #include #include /* for memset */ #include +#include #include "udf_sb.h" @@ -454,7 +455,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, } else if (newIndex > 250) newIndex = 250; newName[newIndex++] = CRC_MARK; - valueCRC = udf_crc(fidName, fidNameLen, 0); + valueCRC = crc_itu_t(0, fidName, fidNameLen); newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];