2005-04-17 02:20:36 +04:00
/*
* super . c
*
* PURPOSE
* Super block routines for the OSTA - UDF ( tm ) filesystem .
*
* DESCRIPTION
* OSTA - UDF ( tm ) = Optical Storage Technology Association
* Universal Disk Format .
*
* This code is based on version 2.00 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 ) 1998 Dave Boynton
* ( C ) 1998 - 2004 Ben Fennema
* ( C ) 2000 Stelias Computing Inc
*
* HISTORY
*
* 09 / 24 / 98 dgb changed to allow compiling outside of kernel , and
* added some debugging .
* 10 / 01 / 98 dgb updated to allow ( some ) possibility of compiling w / 2.0 .34
* 10 / 16 / 98 attempting some multi - session support
* 10 / 17 / 98 added freespace count for " df "
* 11 / 11 / 98 gr added novrs option
* 11 / 26 / 98 dgb added fileset , anchor mount options
2008-02-08 15:20:28 +03:00
* 12 / 06 / 98 blf really hosed things royally . vat / sparing support . sequenced
* vol descs . rewrote option handling based on isofs
2005-04-17 02:20:36 +04:00
* 12 / 20 / 98 find the free space bitmap ( if it exists )
*/
2007-07-19 12:47:43 +04:00
# include "udfdecl.h"
2005-04-17 02:20:36 +04:00
# include <linux/blkdev.h>
# include <linux/slab.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/parser.h>
# include <linux/stat.h>
# include <linux/cdrom.h>
# include <linux/nls.h>
# include <linux/buffer_head.h>
# include <linux/vfs.h>
# include <linux/vmalloc.h>
2008-02-08 15:20:32 +03:00
# include <linux/errno.h>
2008-02-08 15:21:50 +03:00
# include <linux/mount.h>
# include <linux/seq_file.h>
2008-02-03 00:37:07 +03:00
# include <linux/bitmap.h>
2008-04-17 11:47:48 +04:00
# include <linux/crc-itu-t.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# include "udf_sb.h"
# include "udf_i.h"
# include <linux/init.h>
# include <asm/uaccess.h>
# define VDS_POS_PRIMARY_VOL_DESC 0
# define VDS_POS_UNALLOC_SPACE_DESC 1
# define VDS_POS_LOGICAL_VOL_DESC 2
# define VDS_POS_PARTITION_DESC 3
# define VDS_POS_IMP_USE_VOL_DESC 4
# define VDS_POS_VOL_DESC_PTR 5
# define VDS_POS_TERMINATING_DESC 6
# define VDS_POS_LENGTH 7
2008-02-08 15:21:50 +03:00
# define UDF_DEFAULT_BLOCKSIZE 2048
2012-02-06 21:45:27 +04:00
enum { UDF_MAX_LINKS = 0xffff } ;
2005-04-17 02:20:36 +04:00
/* These are the "meat" - everything else is stuffing */
static int udf_fill_super ( struct super_block * , void * , int ) ;
static void udf_put_super ( struct super_block * ) ;
2009-03-16 20:27:37 +03:00
static int udf_sync_fs ( struct super_block * , int ) ;
2005-04-17 02:20:36 +04:00
static int udf_remount_fs ( struct super_block * , int * , char * ) ;
2008-10-15 14:28:03 +04:00
static void udf_load_logicalvolint ( struct super_block * , struct kernel_extent_ad ) ;
static int udf_find_fileset ( struct super_block * , struct kernel_lb_addr * ,
struct kernel_lb_addr * ) ;
2007-07-19 12:47:43 +04:00
static void udf_load_fileset ( struct super_block * , struct buffer_head * ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr * ) ;
2005-04-17 02:20:36 +04:00
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 * ) ;
2006-06-23 13:02:58 +04:00
static int udf_statfs ( struct dentry * , struct kstatfs * ) ;
2011-12-09 06:32:45 +04:00
static int udf_show_options ( struct seq_file * , struct dentry * ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
struct logicalVolIntegrityDescImpUse * udf_sb_lvidiu ( struct udf_sb_info * sbi )
{
2008-02-08 15:20:36 +03:00
struct logicalVolIntegrityDesc * lvid =
( struct logicalVolIntegrityDesc * ) sbi - > s_lvid_bh - > b_data ;
2008-02-08 15:20:30 +03:00
__u32 number_of_partitions = le32_to_cpu ( lvid - > numOfPartitions ) ;
2008-02-08 15:20:36 +03:00
__u32 offset = number_of_partitions * 2 *
sizeof ( uint32_t ) / sizeof ( uint8_t ) ;
2008-02-08 15:20:30 +03:00
return ( struct logicalVolIntegrityDescImpUse * ) & ( lvid - > impUse [ offset ] ) ;
}
2005-04-17 02:20:36 +04:00
/* UDF filesystem type */
2010-07-25 00:46:55 +04:00
static struct dentry * udf_mount ( struct file_system_type * fs_type ,
int flags , const char * dev_name , void * data )
2005-04-17 02:20:36 +04:00
{
2010-07-25 00:46:55 +04:00
return mount_bdev ( fs_type , flags , dev_name , data , udf_fill_super ) ;
2005-04-17 02:20:36 +04:00
}
static struct file_system_type udf_fstype = {
2007-07-21 15:37:18 +04:00
. owner = THIS_MODULE ,
. name = " udf " ,
2010-07-25 00:46:55 +04:00
. mount = udf_mount ,
2007-07-21 15:37:18 +04:00
. kill_sb = kill_block_super ,
. fs_flags = FS_REQUIRES_DEV ,
2005-04-17 02:20:36 +04:00
} ;
2007-07-19 12:47:43 +04:00
static struct kmem_cache * udf_inode_cachep ;
2005-04-17 02:20:36 +04:00
static struct inode * udf_alloc_inode ( struct super_block * sb )
{
struct udf_inode_info * ei ;
2008-02-08 15:20:28 +03:00
ei = kmem_cache_alloc ( udf_inode_cachep , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! ei )
return NULL ;
2006-08-14 10:24:18 +04:00
ei - > i_unique = 0 ;
ei - > i_lenExtents = 0 ;
ei - > i_next_alloc_block = 0 ;
ei - > i_next_alloc_goal = 0 ;
ei - > i_strat4096 = 0 ;
2010-11-16 20:40:47 +03:00
init_rwsem ( & ei - > i_data_sem ) ;
2006-08-14 10:24:18 +04:00
2005-04-17 02:20:36 +04:00
return & ei - > vfs_inode ;
}
2011-01-07 09:49:49 +03:00
static void udf_i_callback ( struct rcu_head * head )
2005-04-17 02:20:36 +04:00
{
2011-01-07 09:49:49 +03:00
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( udf_inode_cachep , UDF_I ( inode ) ) ;
}
2011-01-07 09:49:49 +03:00
static void udf_destroy_inode ( struct inode * inode )
{
call_rcu ( & inode - > i_rcu , udf_i_callback ) ;
}
2008-07-26 06:45:34 +04:00
static void init_once ( void * foo )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct udf_inode_info * ei = ( struct udf_inode_info * ) foo ;
2005-04-17 02:20:36 +04:00
2007-05-17 09:10:57 +04:00
ei - > i_ext . i_data = NULL ;
inode_init_once ( & ei - > vfs_inode ) ;
2005-04-17 02:20:36 +04:00
}
static int init_inodecache ( void )
{
udf_inode_cachep = kmem_cache_create ( " udf_inode_cache " ,
sizeof ( struct udf_inode_info ) ,
2007-07-19 12:47:43 +04:00
0 , ( SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD ) ,
2007-07-20 05:11:58 +04:00
init_once ) ;
2007-07-21 15:37:18 +04:00
if ( ! udf_inode_cachep )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
return 0 ;
}
static void destroy_inodecache ( void )
{
2006-09-27 12:49:40 +04:00
kmem_cache_destroy ( udf_inode_cachep ) ;
2005-04-17 02:20:36 +04:00
}
/* Superblock operations */
2007-02-12 11:55:41 +03:00
static const struct super_operations udf_sb_ops = {
2007-07-21 15:37:18 +04:00
. alloc_inode = udf_alloc_inode ,
. destroy_inode = udf_destroy_inode ,
. write_inode = udf_write_inode ,
2010-06-07 08:43:39 +04:00
. evict_inode = udf_evict_inode ,
2007-07-21 15:37:18 +04:00
. put_super = udf_put_super ,
2009-03-16 20:27:37 +03:00
. sync_fs = udf_sync_fs ,
2007-07-21 15:37:18 +04:00
. statfs = udf_statfs ,
. remount_fs = udf_remount_fs ,
2008-02-08 15:21:50 +03:00
. show_options = udf_show_options ,
2005-04-17 02:20:36 +04:00
} ;
2007-07-19 12:47:43 +04:00
struct udf_options {
2005-04-17 02:20:36 +04:00
unsigned char novrs ;
unsigned int blocksize ;
unsigned int session ;
unsigned int lastblock ;
unsigned int anchor ;
unsigned int volume ;
unsigned short partition ;
unsigned int fileset ;
unsigned int rootdir ;
unsigned int flags ;
2011-07-26 11:18:29 +04:00
umode_t umask ;
2005-04-17 02:20:36 +04:00
gid_t gid ;
uid_t uid ;
2011-07-26 11:18:29 +04:00
umode_t fmode ;
umode_t dmode ;
2005-04-17 02:20:36 +04:00
struct nls_table * nls_map ;
} ;
static int __init init_udf_fs ( void )
{
int err ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
err = init_inodecache ( ) ;
if ( err )
goto out1 ;
err = register_filesystem ( & udf_fstype ) ;
if ( err )
goto out ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
destroy_inodecache ( ) ;
2007-07-21 15:37:18 +04:00
out1 :
2005-04-17 02:20:36 +04:00
return err ;
}
static void __exit exit_udf_fs ( void )
{
unregister_filesystem ( & udf_fstype ) ;
destroy_inodecache ( ) ;
}
module_init ( init_udf_fs )
2007-07-21 15:37:18 +04:00
module_exit ( exit_udf_fs )
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:32 +03:00
static int udf_sb_alloc_partition_maps ( struct super_block * sb , u32 count )
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
sbi - > s_partmaps = kcalloc ( count , sizeof ( struct udf_part_map ) ,
GFP_KERNEL ) ;
if ( ! sbi - > s_partmaps ) {
2011-10-10 12:08:03 +04:00
udf_err ( sb , " Unable to allocate space for %d partition maps \n " ,
count ) ;
2008-02-08 15:20:32 +03:00
sbi - > s_partitions = 0 ;
return - ENOMEM ;
}
sbi - > s_partitions = count ;
return 0 ;
}
2011-12-09 06:32:45 +04:00
static int udf_show_options ( struct seq_file * seq , struct dentry * root )
2008-02-08 15:21:50 +03:00
{
2011-12-09 06:32:45 +04:00
struct super_block * sb = root - > d_sb ;
2008-02-08 15:21:50 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
if ( ! UDF_QUERY_FLAG ( sb , UDF_FLAG_STRICT ) )
seq_puts ( seq , " ,nostrict " ) ;
2009-03-11 17:57:47 +03:00
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_BLOCKSIZE_SET ) )
2008-02-08 15:21:50 +03:00
seq_printf ( seq , " ,bs=%lu " , sb - > s_blocksize ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_UNHIDE ) )
seq_puts ( seq , " ,unhide " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_UNDELETE ) )
seq_puts ( seq , " ,undelete " ) ;
if ( ! UDF_QUERY_FLAG ( sb , UDF_FLAG_USE_AD_IN_ICB ) )
seq_puts ( seq , " ,noadinicb " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_USE_SHORT_AD ) )
seq_puts ( seq , " ,shortad " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_UID_FORGET ) )
seq_puts ( seq , " ,uid=forget " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_UID_IGNORE ) )
seq_puts ( seq , " ,uid=ignore " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_GID_FORGET ) )
seq_puts ( seq , " ,gid=forget " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_GID_IGNORE ) )
seq_puts ( seq , " ,gid=ignore " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_UID_SET ) )
seq_printf ( seq , " ,uid=%u " , sbi - > s_uid ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_GID_SET ) )
seq_printf ( seq , " ,gid=%u " , sbi - > s_gid ) ;
if ( sbi - > s_umask ! = 0 )
2011-07-26 11:18:29 +04:00
seq_printf ( seq , " ,umask=%ho " , sbi - > s_umask ) ;
2008-12-02 15:40:11 +03:00
if ( sbi - > s_fmode ! = UDF_INVALID_MODE )
2011-07-26 11:18:29 +04:00
seq_printf ( seq , " ,mode=%ho " , sbi - > s_fmode ) ;
2008-12-02 15:40:11 +03:00
if ( sbi - > s_dmode ! = UDF_INVALID_MODE )
2011-07-26 11:18:29 +04:00
seq_printf ( seq , " ,dmode=%ho " , sbi - > s_dmode ) ;
2008-02-08 15:21:50 +03:00
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_SESSION_SET ) )
seq_printf ( seq , " ,session=%u " , sbi - > s_session ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_LASTBLOCK_SET ) )
seq_printf ( seq , " ,lastblock=%u " , sbi - > s_last_block ) ;
2009-03-19 18:21:38 +03:00
if ( sbi - > s_anchor ! = 0 )
seq_printf ( seq , " ,anchor=%u " , sbi - > s_anchor ) ;
2008-02-08 15:21:50 +03:00
/*
* volume , partition , fileset and rootdir seem to be ignored
* currently
*/
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_UTF8 ) )
seq_puts ( seq , " ,utf8 " ) ;
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_NLS_MAP ) & & sbi - > s_nls_map )
seq_printf ( seq , " ,iocharset=%s " , sbi - > s_nls_map - > charset ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* udf_parse_options
*
* PURPOSE
* Parse mount options .
*
* DESCRIPTION
* The following mount options are supported :
*
* gid = Set the default group .
* umask = Set the default umask .
2008-11-16 22:52:19 +03:00
* mode = Set the default file permissions .
* dmode = Set the default directory permissions .
2005-04-17 02:20:36 +04:00
* uid = Set the default user .
* bs = Set the block size .
* unhide Show otherwise hidden files .
* undelete Show deleted files in lists .
* adinicb Embed data in the inode ( default )
* noadinicb Don ' t embed data in the inode
* shortad Use short ad ' s
* longad Use long ad ' s ( default )
* nostrict Unset strict conformance
* iocharset = Set the NLS character set
*
* The remaining are for debugging and disaster recovery :
*
2007-07-21 15:37:18 +04:00
* novrs Skip volume sequence recognition
2005-04-17 02:20:36 +04:00
*
* The following expect a offset from 0.
*
* session = Set the CDROM session ( default = last session )
* anchor = Override standard anchor location . ( default = 256 )
* volume = Override the VolumeDesc location . ( unused )
* partition = Override the PartitionDesc location . ( unused )
* lastblock = Set the last block of the filesystem /
*
* The following expect a offset from the partition root .
*
* fileset = Override the fileset block location . ( unused )
* rootdir = Override the root directory location . ( unused )
* WARNING : overriding the rootdir to a non - directory may
* yield highly unpredictable results .
*
* PRE - CONDITIONS
* options Pointer to mount options string .
* uopts Pointer to mount options variable .
*
* POST - CONDITIONS
* < return > 1 Mount options parsed okay .
* < return > 0 Error parsing mount options .
*
* HISTORY
* July 1 , 1997 - Andrew E . Mileski
* Written , tested , and released .
*/
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
enum {
Opt_novrs , Opt_nostrict , Opt_bs , Opt_unhide , Opt_undelete ,
Opt_noadinicb , Opt_adinicb , Opt_shortad , Opt_longad ,
Opt_gid , Opt_uid , Opt_umask , Opt_session , Opt_lastblock ,
Opt_anchor , Opt_volume , Opt_partition , Opt_fileset ,
Opt_rootdir , Opt_utf8 , Opt_iocharset ,
2008-11-16 22:52:19 +03:00
Opt_err , Opt_uforget , Opt_uignore , Opt_gforget , Opt_gignore ,
Opt_fmode , Opt_dmode
2005-04-17 02:20:36 +04:00
} ;
2008-10-13 13:46:57 +04:00
static const match_table_t tokens = {
2007-07-21 15:37:18 +04:00
{ Opt_novrs , " novrs " } ,
{ Opt_nostrict , " nostrict " } ,
{ Opt_bs , " bs=%u " } ,
{ Opt_unhide , " unhide " } ,
{ Opt_undelete , " undelete " } ,
{ Opt_noadinicb , " noadinicb " } ,
{ Opt_adinicb , " adinicb " } ,
{ Opt_shortad , " shortad " } ,
{ Opt_longad , " longad " } ,
{ Opt_uforget , " uid=forget " } ,
{ Opt_uignore , " uid=ignore " } ,
{ Opt_gforget , " gid=forget " } ,
{ Opt_gignore , " gid=ignore " } ,
{ Opt_gid , " gid=%u " } ,
{ Opt_uid , " uid=%u " } ,
{ Opt_umask , " umask=%o " } ,
{ Opt_session , " session=%u " } ,
{ Opt_lastblock , " lastblock=%u " } ,
{ Opt_anchor , " anchor=%u " } ,
{ Opt_volume , " volume=%u " } ,
{ Opt_partition , " partition=%u " } ,
{ Opt_fileset , " fileset=%u " } ,
{ Opt_rootdir , " rootdir=%u " } ,
{ Opt_utf8 , " utf8 " } ,
{ Opt_iocharset , " iocharset=%s " } ,
2008-11-16 22:52:19 +03:00
{ Opt_fmode , " mode=%o " } ,
{ Opt_dmode , " dmode=%o " } ,
2007-07-21 15:37:18 +04:00
{ Opt_err , NULL }
2005-04-17 02:20:36 +04:00
} ;
2008-02-08 15:21:50 +03:00
static int udf_parse_options ( char * options , struct udf_options * uopt ,
bool remount )
2005-04-17 02:20:36 +04:00
{
char * p ;
int option ;
uopt - > novrs = 0 ;
uopt - > partition = 0xFFFF ;
uopt - > session = 0xFFFFFFFF ;
uopt - > lastblock = 0 ;
uopt - > anchor = 0 ;
uopt - > volume = 0xFFFFFFFF ;
uopt - > rootdir = 0xFFFFFFFF ;
uopt - > fileset = 0xFFFFFFFF ;
uopt - > nls_map = NULL ;
if ( ! options )
return 1 ;
2007-07-19 12:47:43 +04:00
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
2005-04-17 02:20:36 +04:00
substring_t args [ MAX_OPT_ARGS ] ;
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
2007-07-19 12:47:43 +04:00
switch ( token ) {
case Opt_novrs :
uopt - > novrs = 1 ;
2009-03-06 11:16:49 +03:00
break ;
2007-07-19 12:47:43 +04:00
case Opt_bs :
if ( match_int ( & args [ 0 ] , & option ) )
return 0 ;
uopt - > blocksize = option ;
2009-03-11 17:57:47 +03:00
uopt - > flags | = ( 1 < < UDF_FLAG_BLOCKSIZE_SET ) ;
2007-07-19 12:47:43 +04:00
break ;
case Opt_unhide :
uopt - > flags | = ( 1 < < UDF_FLAG_UNHIDE ) ;
break ;
case Opt_undelete :
uopt - > flags | = ( 1 < < UDF_FLAG_UNDELETE ) ;
break ;
case Opt_noadinicb :
uopt - > flags & = ~ ( 1 < < UDF_FLAG_USE_AD_IN_ICB ) ;
break ;
case Opt_adinicb :
uopt - > flags | = ( 1 < < UDF_FLAG_USE_AD_IN_ICB ) ;
break ;
case Opt_shortad :
uopt - > flags | = ( 1 < < UDF_FLAG_USE_SHORT_AD ) ;
break ;
case Opt_longad :
uopt - > flags & = ~ ( 1 < < UDF_FLAG_USE_SHORT_AD ) ;
break ;
case Opt_gid :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > gid = option ;
2007-07-31 11:39:40 +04:00
uopt - > flags | = ( 1 < < UDF_FLAG_GID_SET ) ;
2007-07-19 12:47:43 +04:00
break ;
case Opt_uid :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > uid = option ;
2007-07-31 11:39:40 +04:00
uopt - > flags | = ( 1 < < UDF_FLAG_UID_SET ) ;
2007-07-19 12:47:43 +04:00
break ;
case Opt_umask :
if ( match_octal ( args , & option ) )
return 0 ;
uopt - > umask = option ;
break ;
case Opt_nostrict :
uopt - > flags & = ~ ( 1 < < UDF_FLAG_STRICT ) ;
break ;
case Opt_session :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > session = option ;
2008-02-08 15:21:50 +03:00
if ( ! remount )
uopt - > flags | = ( 1 < < UDF_FLAG_SESSION_SET ) ;
2007-07-19 12:47:43 +04:00
break ;
case Opt_lastblock :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > lastblock = option ;
2008-02-08 15:21:50 +03:00
if ( ! remount )
uopt - > flags | = ( 1 < < UDF_FLAG_LASTBLOCK_SET ) ;
2007-07-19 12:47:43 +04:00
break ;
case Opt_anchor :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > anchor = option ;
break ;
case Opt_volume :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > volume = option ;
break ;
case Opt_partition :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > partition = option ;
break ;
case Opt_fileset :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > fileset = option ;
break ;
case Opt_rootdir :
if ( match_int ( args , & option ) )
return 0 ;
uopt - > rootdir = option ;
break ;
case Opt_utf8 :
uopt - > flags | = ( 1 < < UDF_FLAG_UTF8 ) ;
break ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_UDF_NLS
2007-07-19 12:47:43 +04:00
case Opt_iocharset :
uopt - > nls_map = load_nls ( args [ 0 ] . from ) ;
uopt - > flags | = ( 1 < < UDF_FLAG_NLS_MAP ) ;
break ;
2005-04-17 02:20:36 +04:00
# endif
2007-07-19 12:47:43 +04:00
case Opt_uignore :
uopt - > flags | = ( 1 < < UDF_FLAG_UID_IGNORE ) ;
break ;
case Opt_uforget :
uopt - > flags | = ( 1 < < UDF_FLAG_UID_FORGET ) ;
break ;
case Opt_gignore :
uopt - > flags | = ( 1 < < UDF_FLAG_GID_IGNORE ) ;
break ;
case Opt_gforget :
uopt - > flags | = ( 1 < < UDF_FLAG_GID_FORGET ) ;
break ;
2008-11-16 22:52:19 +03:00
case Opt_fmode :
if ( match_octal ( args , & option ) )
return 0 ;
uopt - > fmode = option & 0777 ;
break ;
case Opt_dmode :
if ( match_octal ( args , & option ) )
return 0 ;
uopt - > dmode = option & 0777 ;
break ;
2007-07-19 12:47:43 +04:00
default :
2011-10-10 12:08:05 +04:00
pr_err ( " bad mount option \" %s \" or missing value \n " , p ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
}
return 1 ;
}
2007-07-19 12:47:43 +04:00
static int udf_remount_fs ( struct super_block * sb , int * flags , char * options )
2005-04-17 02:20:36 +04:00
{
struct udf_options uopt ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2010-05-19 15:16:40 +04:00
int error = 0 ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
uopt . flags = sbi - > s_flags ;
uopt . uid = sbi - > s_uid ;
uopt . gid = sbi - > s_gid ;
uopt . umask = sbi - > s_umask ;
2008-11-16 22:52:19 +03:00
uopt . fmode = sbi - > s_fmode ;
uopt . dmode = sbi - > s_dmode ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:21:50 +03:00
if ( ! udf_parse_options ( options , & uopt , true ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2010-10-21 00:17:28 +04:00
write_lock ( & sbi - > s_cred_lock ) ;
2008-02-08 15:20:30 +03:00
sbi - > s_flags = uopt . flags ;
sbi - > s_uid = uopt . uid ;
sbi - > s_gid = uopt . gid ;
sbi - > s_umask = uopt . umask ;
2008-11-16 22:52:19 +03:00
sbi - > s_fmode = uopt . fmode ;
sbi - > s_dmode = uopt . dmode ;
2010-10-21 00:17:28 +04:00
write_unlock ( & sbi - > s_cred_lock ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ) {
int write_rev = le16_to_cpu ( udf_sb_lvidiu ( sbi ) - > minUDFWriteRev ) ;
2005-04-17 02:20:36 +04:00
if ( write_rev > UDF_MAX_WRITE_VERSION )
* flags | = MS_RDONLY ;
}
2010-05-19 15:16:40 +04:00
if ( ( * flags & MS_RDONLY ) = = ( sb - > s_flags & MS_RDONLY ) )
goto out_unlock ;
2010-05-19 18:28:56 +04:00
if ( * flags & MS_RDONLY )
2005-04-17 02:20:36 +04:00
udf_close_lvid ( sb ) ;
2010-05-19 18:28:56 +04:00
else
2005-04-17 02:20:36 +04:00
udf_open_lvid ( sb ) ;
2010-05-19 15:16:40 +04:00
out_unlock :
return error ;
2005-04-17 02:20:36 +04:00
}
2009-03-19 18:21:38 +03:00
/* Check Volume Structure Descriptors (ECMA 167 2/9.1) */
/* We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
static loff_t udf_check_vsd ( struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
struct volStructDesc * vsd = NULL ;
2008-04-08 16:02:11 +04:00
loff_t sector = 32768 ;
2005-04-17 02:20:36 +04:00
int sectorsize ;
struct buffer_head * bh = NULL ;
2007-07-19 12:47:43 +04:00
int nsr02 = 0 ;
int nsr03 = 0 ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
sbi = UDF_SB ( sb ) ;
2005-04-17 02:20:36 +04:00
if ( sb - > s_blocksize < sizeof ( struct volStructDesc ) )
sectorsize = sizeof ( struct volStructDesc ) ;
else
sectorsize = sb - > s_blocksize ;
2008-02-08 15:20:30 +03:00
sector + = ( sbi - > s_session < < sb - > s_blocksize_bits ) ;
2005-04-17 02:20:36 +04:00
udf_debug ( " Starting at sector %u (%ld byte sectors) \n " ,
2008-04-14 19:13:01 +04:00
( unsigned int ) ( sector > > sb - > s_blocksize_bits ) ,
sb - > s_blocksize ) ;
2005-04-17 02:20:36 +04:00
/* Process the sequence (if applicable) */
2007-07-19 12:47:43 +04:00
for ( ; ! nsr02 & & ! nsr03 ; sector + = sectorsize ) {
2005-04-17 02:20:36 +04:00
/* Read a block */
bh = udf_tread ( sb , sector > > sb - > s_blocksize_bits ) ;
if ( ! bh )
break ;
/* Look for ISO descriptors */
vsd = ( struct volStructDesc * ) ( bh - > b_data +
2008-02-08 15:20:28 +03:00
( sector & ( sb - > s_blocksize - 1 ) ) ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( vsd - > stdIdent [ 0 ] = = 0 ) {
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
break ;
2008-02-08 15:20:28 +03:00
} else if ( ! strncmp ( vsd - > stdIdent , VSD_STD_ID_CD001 ,
VSD_STD_ID_LEN ) ) {
2007-07-19 12:47:43 +04:00
switch ( vsd - > structType ) {
case 0 :
udf_debug ( " ISO9660 Boot Record found \n " ) ;
break ;
case 1 :
2011-10-10 12:08:07 +04:00
udf_debug ( " ISO9660 Primary Volume Descriptor found \n " ) ;
2007-07-19 12:47:43 +04:00
break ;
case 2 :
2011-10-10 12:08:07 +04:00
udf_debug ( " ISO9660 Supplementary Volume Descriptor found \n " ) ;
2007-07-19 12:47:43 +04:00
break ;
case 3 :
2011-10-10 12:08:07 +04:00
udf_debug ( " ISO9660 Volume Partition Descriptor found \n " ) ;
2007-07-19 12:47:43 +04:00
break ;
case 255 :
2011-10-10 12:08:07 +04:00
udf_debug ( " ISO9660 Volume Descriptor Set Terminator found \n " ) ;
2007-07-19 12:47:43 +04:00
break ;
default :
udf_debug ( " ISO9660 VRS (%u) found \n " ,
vsd - > structType ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:28 +03:00
} else if ( ! strncmp ( vsd - > stdIdent , VSD_STD_ID_BEA01 ,
VSD_STD_ID_LEN ) )
; /* nothing */
else if ( ! strncmp ( vsd - > stdIdent , VSD_STD_ID_TEA01 ,
VSD_STD_ID_LEN ) ) {
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
break ;
2008-02-08 15:20:28 +03:00
} else if ( ! strncmp ( vsd - > stdIdent , VSD_STD_ID_NSR02 ,
VSD_STD_ID_LEN ) )
2005-04-17 02:20:36 +04:00
nsr02 = sector ;
2008-02-08 15:20:28 +03:00
else if ( ! strncmp ( vsd - > stdIdent , VSD_STD_ID_NSR03 ,
VSD_STD_ID_LEN ) )
2005-04-17 02:20:36 +04:00
nsr03 = sector ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
}
if ( nsr03 )
return nsr03 ;
else if ( nsr02 )
return nsr02 ;
2008-02-08 15:20:30 +03:00
else if ( sector - ( sbi - > s_session < < sb - > s_blocksize_bits ) = = 32768 )
2005-04-17 02:20:36 +04:00
return - 1 ;
else
return 0 ;
}
2008-02-08 15:20:28 +03:00
static int udf_find_fileset ( struct super_block * sb ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr * fileset ,
struct kernel_lb_addr * root )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
long lastblock ;
uint16_t ident ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi ;
2005-04-17 02:20:36 +04:00
if ( fileset - > logicalBlockNum ! = 0xFFFFFFFF | |
2007-07-19 12:47:43 +04:00
fileset - > partitionReferenceNum ! = 0xFFFF ) {
2008-10-15 14:29:03 +04:00
bh = udf_read_ptagged ( sb , fileset , 0 , & ident ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
if ( ! bh ) {
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-21 15:37:18 +04:00
} else if ( ident ! = TAG_IDENT_FSD ) {
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2007-07-19 12:47:43 +04:00
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:30 +03:00
sbi = UDF_SB ( sb ) ;
2008-02-08 15:20:28 +03:00
if ( ! bh ) {
/* Search backwards through the partitions */
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr newfileset ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
/* --> cvg: FIXME - is it reasonable? */
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-19 12:47:43 +04:00
2008-02-08 15:20:30 +03:00
for ( newfileset . partitionReferenceNum = sbi - > s_partitions - 1 ;
2007-07-19 12:47:43 +04:00
( newfileset . partitionReferenceNum ! = 0xFFFF & &
fileset - > logicalBlockNum = = 0xFFFFFFFF & &
fileset - > partitionReferenceNum = = 0xFFFF ) ;
newfileset . partitionReferenceNum - - ) {
2008-02-08 15:20:30 +03:00
lastblock = sbi - > s_partmaps
[ newfileset . partitionReferenceNum ]
. s_partition_len ;
2005-04-17 02:20:36 +04:00
newfileset . logicalBlockNum = 0 ;
2007-07-19 12:47:43 +04:00
do {
2008-10-15 14:29:03 +04:00
bh = udf_read_ptagged ( sb , & newfileset , 0 ,
2008-02-08 15:20:28 +03:00
& ident ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
newfileset . logicalBlockNum + + ;
2005-04-17 02:20:36 +04:00
continue ;
}
2007-07-19 12:47:43 +04:00
switch ( ident ) {
case TAG_IDENT_SBD :
2007-07-21 15:37:18 +04:00
{
struct spaceBitmapDesc * sp ;
2008-02-08 15:20:36 +03:00
sp = ( struct spaceBitmapDesc * )
bh - > b_data ;
2007-07-21 15:37:18 +04:00
newfileset . logicalBlockNum + = 1 +
( ( le32_to_cpu ( sp - > numOfBytes ) +
2008-02-08 15:20:36 +03:00
sizeof ( struct spaceBitmapDesc )
- 1 ) > > sb - > s_blocksize_bits ) ;
2007-07-21 15:37:18 +04:00
brelse ( bh ) ;
break ;
}
2007-07-19 12:47:43 +04:00
case TAG_IDENT_FSD :
2007-07-21 15:37:18 +04:00
* fileset = newfileset ;
break ;
2007-07-19 12:47:43 +04:00
default :
2007-07-21 15:37:18 +04:00
newfileset . logicalBlockNum + + ;
brelse ( bh ) ;
bh = NULL ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
} while ( newfileset . logicalBlockNum < lastblock & &
fileset - > logicalBlockNum = = 0xFFFFFFFF & &
fileset - > partitionReferenceNum = = 0xFFFF ) ;
2005-04-17 02:20:36 +04:00
}
}
if ( ( fileset - > logicalBlockNum ! = 0xFFFFFFFF | |
2007-07-19 12:47:43 +04:00
fileset - > partitionReferenceNum ! = 0xFFFF ) & & bh ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " Fileset at block=%d, partition=%d \n " ,
2007-07-19 12:47:43 +04:00
fileset - > logicalBlockNum ,
fileset - > partitionReferenceNum ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
sbi - > s_partition = fileset - > partitionReferenceNum ;
2005-04-17 02:20:36 +04:00
udf_load_fileset ( sb , bh , root ) ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
return 1 ;
}
2008-04-01 18:50:35 +04:00
static int udf_load_pvoldesc ( struct super_block * sb , sector_t block )
2005-04-17 02:20:36 +04:00
{
struct primaryVolDesc * pvoldesc ;
2008-11-16 21:01:44 +03:00
struct ustr * instr , * outstr ;
2008-04-01 18:50:35 +04:00
struct buffer_head * bh ;
uint16_t ident ;
2008-11-16 21:01:44 +03:00
int ret = 1 ;
instr = kmalloc ( sizeof ( struct ustr ) , GFP_NOFS ) ;
if ( ! instr )
return 1 ;
outstr = kmalloc ( sizeof ( struct ustr ) , GFP_NOFS ) ;
if ( ! outstr )
goto out1 ;
2008-04-01 18:50:35 +04:00
bh = udf_read_tagged ( sb , block , block , & ident ) ;
if ( ! bh )
2008-11-16 21:01:44 +03:00
goto out2 ;
2008-04-01 18:50:35 +04:00
BUG_ON ( ident ! = TAG_IDENT_PVD ) ;
2005-04-17 02:20:36 +04:00
pvoldesc = ( struct primaryVolDesc * ) bh - > b_data ;
2008-02-10 13:25:31 +03:00
if ( udf_disk_stamp_to_time ( & UDF_SB ( sb ) - > s_record_time ,
pvoldesc - > recordingDateAndTime ) ) {
2008-02-10 13:29:10 +03:00
# ifdef UDFFS_DEBUG
2008-10-15 14:28:03 +04:00
struct timestamp * ts = & pvoldesc - > recordingDateAndTime ;
2011-10-10 12:08:07 +04:00
udf_debug ( " recording time %04u/%02u/%02u %02u:%02u (%x) \n " ,
2008-02-10 13:29:10 +03:00
le16_to_cpu ( ts - > year ) , ts - > month , ts - > day , ts - > hour ,
ts - > minute , le16_to_cpu ( ts - > typeAndTimezone ) ) ;
# endif
2005-04-17 02:20:36 +04:00
}
2008-11-16 21:01:44 +03:00
if ( ! udf_build_ustr ( instr , pvoldesc - > volIdent , 32 ) )
if ( udf_CS0toUTF8 ( outstr , instr ) ) {
strncpy ( UDF_SB ( sb ) - > s_volume_ident , outstr - > u_name ,
outstr - > u_len > 31 ? 31 : outstr - > u_len ) ;
2008-02-08 15:20:36 +03:00
udf_debug ( " volIdent[] = '%s' \n " ,
2011-10-10 12:08:07 +04:00
UDF_SB ( sb ) - > s_volume_ident ) ;
2005-04-17 02:20:36 +04:00
}
2008-11-16 21:01:44 +03:00
if ( ! udf_build_ustr ( instr , pvoldesc - > volSetIdent , 128 ) )
if ( udf_CS0toUTF8 ( outstr , instr ) )
udf_debug ( " volSetIdent[] = '%s' \n " , outstr - > u_name ) ;
2008-04-01 18:50:35 +04:00
brelse ( bh ) ;
2008-11-16 21:01:44 +03:00
ret = 0 ;
out2 :
kfree ( outstr ) ;
out1 :
kfree ( instr ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2011-10-23 14:28:32 +04:00
struct inode * udf_find_metadata_inode_efe ( struct super_block * sb ,
u32 meta_file_loc , u32 partition_num )
{
struct kernel_lb_addr addr ;
struct inode * metadata_fe ;
addr . logicalBlockNum = meta_file_loc ;
addr . partitionReferenceNum = partition_num ;
metadata_fe = udf_iget ( sb , & addr ) ;
if ( metadata_fe = = NULL )
udf_warn ( sb , " metadata inode efe not found \n " ) ;
else if ( UDF_I ( metadata_fe ) - > i_alloc_type ! = ICBTAG_FLAG_AD_SHORT ) {
udf_warn ( sb , " metadata inode efe does not have short allocation descriptors! \n " ) ;
iput ( metadata_fe ) ;
metadata_fe = NULL ;
}
return metadata_fe ;
}
2008-04-08 22:37:21 +04:00
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 ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr addr ;
2008-04-08 22:37:21 +04:00
map = & sbi - > s_partmaps [ partition ] ;
mdata = & map - > s_type_specific . s_metadata ;
/* metadata address */
udf_debug ( " Metadata file location: block = %d part = %d \n " ,
2011-10-23 14:28:32 +04:00
mdata - > s_meta_file_loc , map - > s_partition_num ) ;
2008-04-08 22:37:21 +04:00
2011-10-23 14:28:32 +04:00
mdata - > s_metadata_fe = udf_find_metadata_inode_efe ( sb ,
mdata - > s_meta_file_loc , map - > s_partition_num ) ;
2008-04-08 22:37:21 +04:00
if ( mdata - > s_metadata_fe = = NULL ) {
2011-10-23 14:28:32 +04:00
/* mirror file entry */
udf_debug ( " Mirror metadata file location: block = %d part = %d \n " ,
mdata - > s_mirror_file_loc , map - > s_partition_num ) ;
2008-04-08 22:37:21 +04:00
2011-10-23 14:28:32 +04:00
mdata - > s_mirror_fe = udf_find_metadata_inode_efe ( sb ,
mdata - > s_mirror_file_loc , map - > s_partition_num ) ;
2008-04-08 22:37:21 +04:00
2011-10-23 14:28:32 +04:00
if ( mdata - > s_mirror_fe = = NULL ) {
udf_err ( sb , " Both metadata and mirror metadata inode efe can not found \n " ) ;
2008-04-08 22:37:21 +04:00
goto error_exit ;
2011-10-23 14:28:32 +04:00
}
2008-04-08 22:37:21 +04:00
}
/*
* 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 " ,
2011-10-10 12:08:07 +04:00
addr . logicalBlockNum , addr . partitionReferenceNum ) ;
2008-04-08 22:37:21 +04:00
2008-10-15 14:29:03 +04:00
mdata - > s_bitmap_fe = udf_iget ( sb , & addr ) ;
2008-04-08 22:37:21 +04:00
if ( mdata - > s_bitmap_fe = = NULL ) {
if ( sb - > s_flags & MS_RDONLY )
2011-10-10 12:08:04 +04:00
udf_warn ( sb , " bitmap inode efe not found but it's ok since the disc is mounted read-only \n " ) ;
2008-04-08 22:37:21 +04:00
else {
2011-10-10 12:08:03 +04:00
udf_err ( sb , " bitmap inode efe not found and attempted read-write mount \n " ) ;
2008-04-08 22:37:21 +04:00
goto error_exit ;
}
}
}
udf_debug ( " udf_load_metadata_files Ok \n " ) ;
return 0 ;
error_exit :
return 1 ;
}
2007-07-21 15:37:18 +04:00
static void udf_load_fileset ( struct super_block * sb , struct buffer_head * bh ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr * root )
2005-04-17 02:20:36 +04:00
{
struct fileSetDesc * fset ;
fset = ( struct fileSetDesc * ) bh - > b_data ;
* root = lelb_to_cpu ( fset - > rootDirectoryICB . extLocation ) ;
2008-02-08 15:20:30 +03:00
UDF_SB ( sb ) - > s_serial_number = le16_to_cpu ( fset - > descTag . tagSerialNum ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
udf_debug ( " Rootdir at block=%d, partition=%d \n " ,
root - > logicalBlockNum , root - > partitionReferenceNum ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:34 +03:00
int udf_compute_nr_groups ( struct super_block * sb , u32 partition )
{
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2008-02-14 18:15:45 +03:00
return DIV_ROUND_UP ( map - > s_partition_len +
( sizeof ( struct spaceBitmapDesc ) < < 3 ) ,
sb - > s_blocksize * 8 ) ;
2008-02-08 15:20:34 +03:00
}
2008-02-08 15:20:33 +03:00
static struct udf_bitmap * udf_sb_alloc_bitmap ( struct super_block * sb , u32 index )
{
struct udf_bitmap * bitmap ;
int nr_groups ;
int size ;
2008-02-08 15:20:34 +03:00
nr_groups = udf_compute_nr_groups ( sb , index ) ;
2008-02-08 15:20:33 +03:00
size = sizeof ( struct udf_bitmap ) +
( sizeof ( struct buffer_head * ) * nr_groups ) ;
if ( size < = PAGE_SIZE )
2010-11-05 06:08:04 +03:00
bitmap = kzalloc ( size , GFP_KERNEL ) ;
2008-02-08 15:20:33 +03:00
else
2010-11-05 06:08:04 +03:00
bitmap = vzalloc ( size ) ; /* TODO: get rid of vzalloc */
2008-02-08 15:20:33 +03:00
2012-02-01 02:42:10 +04:00
if ( bitmap = = NULL )
2008-02-08 15:20:33 +03:00
return NULL ;
bitmap - > s_block_bitmap = ( struct buffer_head * * ) ( bitmap + 1 ) ;
bitmap - > s_nr_groups = nr_groups ;
return bitmap ;
}
2008-04-02 14:26:36 +04:00
static int udf_fill_partdesc_info ( struct super_block * sb ,
struct partitionDesc * p , int p_index )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:30 +03:00
struct udf_part_map * map ;
2008-02-10 13:33:08 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2008-04-02 14:26:36 +04:00
struct partitionHeaderDesc * phd ;
2008-02-10 13:33:08 +03:00
2008-04-02 14:26:36 +04:00
map = & sbi - > s_partmaps [ p_index ] ;
2008-02-10 13:33:08 +03:00
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 ;
2011-10-10 12:08:07 +04:00
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 ) ;
2008-02-10 13:33:08 +03:00
if ( strcmp ( p - > partitionContents . ident , PD_PARTITION_CONTENTS_NSR02 ) & &
strcmp ( p - > partitionContents . ident , PD_PARTITION_CONTENTS_NSR03 ) )
2008-04-02 14:26:36 +04:00
return 0 ;
2008-02-10 13:33:08 +03:00
phd = ( struct partitionHeaderDesc * ) p - > partitionContentsUse ;
if ( phd - > unallocSpaceTable . extLength ) {
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr loc = {
2008-02-10 13:33:08 +03:00
. logicalBlockNum = le32_to_cpu (
phd - > unallocSpaceTable . extPosition ) ,
2008-04-02 14:26:36 +04:00
. partitionReferenceNum = p_index ,
2008-02-10 13:33:08 +03:00
} ;
2008-10-15 14:29:03 +04:00
map - > s_uspace . s_table = udf_iget ( sb , & loc ) ;
2008-02-10 13:33:08 +03:00
if ( ! map - > s_uspace . s_table ) {
udf_debug ( " cannot load unallocSpaceTable (part %d) \n " ,
2011-10-10 12:08:07 +04:00
p_index ) ;
2008-04-02 14:26:36 +04:00
return 1 ;
2008-02-10 13:33:08 +03:00
}
map - > s_partition_flags | = UDF_PART_FLAG_UNALLOC_TABLE ;
udf_debug ( " unallocSpaceTable (part %d) @ %ld \n " ,
2011-10-10 12:08:07 +04:00
p_index , map - > s_uspace . s_table - > i_ino ) ;
2008-02-10 13:33:08 +03:00
}
if ( phd - > unallocSpaceBitmap . extLength ) {
2008-04-02 14:26:36 +04:00
struct udf_bitmap * bitmap = udf_sb_alloc_bitmap ( sb , p_index ) ;
if ( ! bitmap )
return 1 ;
2008-02-10 13:33:08 +03:00
map - > s_uspace . s_bitmap = bitmap ;
2008-04-01 20:08:51 +04:00
bitmap - > s_extLength = le32_to_cpu (
2008-02-10 13:33:08 +03:00
phd - > unallocSpaceBitmap . extLength ) ;
2008-04-01 20:08:51 +04:00
bitmap - > s_extPosition = le32_to_cpu (
2008-02-10 13:33:08 +03:00
phd - > unallocSpaceBitmap . extPosition ) ;
2008-04-01 20:08:51 +04:00
map - > s_partition_flags | = UDF_PART_FLAG_UNALLOC_BITMAP ;
2011-10-10 12:08:07 +04:00
udf_debug ( " unallocSpaceBitmap (part %d) @ %d \n " ,
p_index , bitmap - > s_extPosition ) ;
2008-02-10 13:33:08 +03:00
}
if ( phd - > partitionIntegrityTable . extLength )
2008-04-02 14:26:36 +04:00
udf_debug ( " partitionIntegrityTable (part %d) \n " , p_index ) ;
2008-02-10 13:33:08 +03:00
if ( phd - > freedSpaceTable . extLength ) {
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr loc = {
2008-02-10 13:33:08 +03:00
. logicalBlockNum = le32_to_cpu (
phd - > freedSpaceTable . extPosition ) ,
2008-04-02 14:26:36 +04:00
. partitionReferenceNum = p_index ,
2008-02-10 13:33:08 +03:00
} ;
2008-10-15 14:29:03 +04:00
map - > s_fspace . s_table = udf_iget ( sb , & loc ) ;
2008-02-10 13:33:08 +03:00
if ( ! map - > s_fspace . s_table ) {
2008-04-02 14:26:36 +04:00
udf_debug ( " cannot load freedSpaceTable (part %d) \n " ,
2011-10-10 12:08:07 +04:00
p_index ) ;
2008-04-02 14:26:36 +04:00
return 1 ;
2008-02-10 13:33:08 +03:00
}
map - > s_partition_flags | = UDF_PART_FLAG_FREED_TABLE ;
udf_debug ( " freedSpaceTable (part %d) @ %ld \n " ,
2011-10-10 12:08:07 +04:00
p_index , map - > s_fspace . s_table - > i_ino ) ;
2008-02-10 13:33:08 +03:00
}
if ( phd - > freedSpaceBitmap . extLength ) {
2008-04-02 14:26:36 +04:00
struct udf_bitmap * bitmap = udf_sb_alloc_bitmap ( sb , p_index ) ;
if ( ! bitmap )
return 1 ;
2008-02-10 13:33:08 +03:00
map - > s_fspace . s_bitmap = bitmap ;
2008-04-01 20:08:51 +04:00
bitmap - > s_extLength = le32_to_cpu (
2008-02-10 13:33:08 +03:00
phd - > freedSpaceBitmap . extLength ) ;
2008-04-01 20:08:51 +04:00
bitmap - > s_extPosition = le32_to_cpu (
2008-02-10 13:33:08 +03:00
phd - > freedSpaceBitmap . extPosition ) ;
2008-04-01 20:08:51 +04:00
map - > s_partition_flags | = UDF_PART_FLAG_FREED_BITMAP ;
2011-10-10 12:08:07 +04:00
udf_debug ( " freedSpaceBitmap (part %d) @ %d \n " ,
p_index , bitmap - > s_extPosition ) ;
2008-02-10 13:33:08 +03:00
}
2008-04-02 14:26:36 +04:00
return 0 ;
}
2009-11-30 21:47:55 +03:00
static void udf_find_vat_block ( struct super_block * sb , int p_index ,
int type1_index , sector_t start_block )
2008-04-02 18:01:35 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct udf_part_map * map = & sbi - > s_partmaps [ p_index ] ;
2009-11-30 21:47:55 +03:00
sector_t vat_block ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr ino ;
2009-11-30 21:47:55 +03:00
/*
* VAT file entry is in the last recorded block . Some broken disks have
* it a few blocks before so try a bit harder . . .
*/
ino . partitionReferenceNum = type1_index ;
for ( vat_block = start_block ;
vat_block > = map - > s_partition_root & &
vat_block > = start_block - 3 & &
! sbi - > s_vat_inode ; vat_block - - ) {
ino . logicalBlockNum = vat_block - map - > s_partition_root ;
sbi - > s_vat_inode = udf_iget ( sb , & ino ) ;
}
}
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 ] ;
2008-04-08 04:08:53 +04:00
struct buffer_head * bh = NULL ;
struct udf_inode_info * vati ;
uint32_t pos ;
struct virtualAllocationTable20 * vat20 ;
2009-07-14 21:30:23 +04:00
sector_t blocks = sb - > s_bdev - > bd_inode - > i_size > > sb - > s_blocksize_bits ;
2008-04-02 18:01:35 +04:00
2009-11-30 21:47:55 +03:00
udf_find_vat_block ( sb , p_index , type1_index , sbi - > s_last_block ) ;
2009-07-14 21:30:23 +04:00
if ( ! sbi - > s_vat_inode & &
sbi - > s_last_block ! = blocks - 1 ) {
2011-10-10 12:08:05 +04:00
pr_notice ( " Failed to read VAT inode from the last recorded block (%lu), retrying with the last block of the device (%lu). \n " ,
( unsigned long ) sbi - > s_last_block ,
( unsigned long ) blocks - 1 ) ;
2009-11-30 21:47:55 +03:00
udf_find_vat_block ( sb , p_index , type1_index , blocks - 1 ) ;
2009-07-14 21:30:23 +04:00
}
2008-04-02 18:01:35 +04:00
if ( ! sbi - > s_vat_inode )
return 1 ;
if ( map - > s_partition_type = = UDF_VIRTUAL_MAP15 ) {
2008-04-14 19:06:36 +04:00
map - > s_type_specific . s_virtual . s_start_offset = 0 ;
2008-04-02 18:01:35 +04:00
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 ) {
2008-04-08 04:08:53 +04:00
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 ;
}
2008-04-02 18:01:35 +04:00
map - > s_type_specific . s_virtual . s_start_offset =
2008-04-14 19:06:36 +04:00
le16_to_cpu ( vat20 - > lengthHeader ) ;
2008-04-02 18:01:35 +04:00
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 ;
}
2008-04-02 14:26:36 +04:00
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 ) ;
2008-04-02 18:01:35 +04:00
int i , type1_idx ;
2008-04-02 14:26:36 +04:00
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 ) ;
2008-04-02 18:01:35 +04:00
2008-04-08 22:37:21 +04:00
/* First scan for TYPE1, SPARABLE and METADATA partitions */
2008-04-02 14:26:36 +04:00
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 ) ;
2008-04-02 18:01:35 +04:00
if ( map - > s_partition_num = = partitionNumber & &
( map - > s_partition_type = = UDF_TYPE1_MAP15 | |
map - > s_partition_type = = UDF_SPARABLE_MAP15 ) )
2008-04-02 14:26:36 +04:00
break ;
}
2008-04-02 18:01:35 +04:00
if ( i > = sbi - > s_partitions ) {
2008-04-02 14:26:36 +04:00
udf_debug ( " Partition (%d) not found in partition map \n " ,
partitionNumber ) ;
goto out_bh ;
}
2008-02-10 13:33:08 +03:00
2008-04-02 14:26:36 +04:00
ret = udf_fill_partdesc_info ( sb , p , i ) ;
2008-04-02 18:01:35 +04:00
/*
2008-04-08 22:37:21 +04:00
* Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
* PHYSICAL partitions are already set up
2008-04-02 18:01:35 +04:00
*/
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 | |
2008-04-08 22:37:21 +04:00
map - > s_partition_type = = UDF_VIRTUAL_MAP20 | |
map - > s_partition_type = = UDF_METADATA_MAP25 ) )
2008-04-02 18:01:35 +04:00
break ;
}
if ( i > = sbi - > s_partitions )
goto out_bh ;
ret = udf_fill_partdesc_info ( sb , p , i ) ;
if ( ret )
goto out_bh ;
2008-04-08 22:37:21 +04:00
if ( map - > s_partition_type = = UDF_METADATA_MAP25 ) {
ret = udf_load_metadata_files ( sb , i ) ;
if ( ret ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb , " error loading MetaData partition map %d \n " ,
i ) ;
2008-04-08 22:37:21 +04:00
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 ;
2011-10-10 12:08:05 +04:00
pr_notice ( " Filesystem marked read-only because writing to pseudooverwrite partition is not implemented \n " ) ;
2008-04-08 22:37:21 +04:00
}
2008-04-01 18:50:35 +04:00
out_bh :
2008-04-01 20:08:51 +04:00
/* In case loading failed, we handle cleanup in udf_fill_super */
2008-04-01 18:50:35 +04:00
brelse ( bh ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2008-04-01 18:50:35 +04:00
static int udf_load_logicalvol ( struct super_block * sb , sector_t block ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr * fileset )
2005-04-17 02:20:36 +04:00
{
struct logicalVolDesc * lvd ;
int i , j , offset ;
uint8_t type ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2008-02-08 15:20:36 +03:00
struct genericPartitionMap * gpm ;
2008-04-01 18:50:35 +04:00
uint16_t ident ;
struct buffer_head * bh ;
int ret = 0 ;
2005-04-17 02:20:36 +04:00
2008-04-01 18:50:35 +04:00
bh = udf_read_tagged ( sb , block , block , & ident ) ;
if ( ! bh )
return 1 ;
BUG_ON ( ident ! = TAG_IDENT_LVD ) ;
2005-04-17 02:20:36 +04:00
lvd = ( struct logicalVolDesc * ) bh - > b_data ;
2008-02-08 15:20:32 +03:00
i = udf_sb_alloc_partition_maps ( sb , le32_to_cpu ( lvd - > numPartitionMaps ) ) ;
2008-04-01 18:50:35 +04:00
if ( i ! = 0 ) {
ret = i ;
goto out_bh ;
}
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
for ( i = 0 , offset = 0 ;
2008-02-08 15:20:30 +03:00
i < sbi - > s_partitions & & offset < le32_to_cpu ( lvd - > mapTableLength ) ;
2008-02-08 15:20:36 +03:00
i + + , offset + = gpm - > partitionMapLength ) {
struct udf_part_map * map = & sbi - > s_partmaps [ i ] ;
gpm = ( struct genericPartitionMap * )
& ( lvd - > partitionMaps [ offset ] ) ;
type = gpm - > partitionMapType ;
2007-07-19 12:47:43 +04:00
if ( type = = 1 ) {
2008-02-08 15:20:36 +03:00
struct genericPartitionMap1 * gpm1 =
( struct genericPartitionMap1 * ) gpm ;
2008-02-08 15:20:30 +03:00
map - > s_partition_type = UDF_TYPE1_MAP15 ;
map - > s_volumeseqnum = le16_to_cpu ( gpm1 - > volSeqNum ) ;
map - > s_partition_num = le16_to_cpu ( gpm1 - > partitionNum ) ;
map - > s_partition_func = NULL ;
2007-07-19 12:47:43 +04:00
} else if ( type = = 2 ) {
2008-02-08 15:20:36 +03:00
struct udfPartitionMap2 * upm2 =
( struct udfPartitionMap2 * ) gpm ;
if ( ! strncmp ( upm2 - > partIdent . ident , UDF_ID_VIRTUAL ,
strlen ( UDF_ID_VIRTUAL ) ) ) {
u16 suf =
le16_to_cpu ( ( ( __le16 * ) upm2 - > partIdent .
identSuffix ) [ 0 ] ) ;
2008-04-08 03:16:32 +04:00
if ( suf < 0x0200 ) {
2008-02-08 15:20:36 +03:00
map - > s_partition_type =
UDF_VIRTUAL_MAP15 ;
map - > s_partition_func =
udf_get_pblock_virt15 ;
2008-04-08 03:16:32 +04:00
} else {
2008-02-08 15:20:36 +03:00
map - > s_partition_type =
UDF_VIRTUAL_MAP20 ;
map - > s_partition_func =
udf_get_pblock_virt20 ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
} else if ( ! strncmp ( upm2 - > partIdent . ident ,
UDF_ID_SPARABLE ,
strlen ( UDF_ID_SPARABLE ) ) ) {
2005-04-17 02:20:36 +04:00
uint32_t loc ;
struct sparingTable * st ;
2008-02-08 15:20:36 +03:00
struct sparablePartitionMap * spm =
( struct sparablePartitionMap * ) gpm ;
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:30 +03:00
map - > s_partition_type = UDF_SPARABLE_MAP15 ;
2008-02-08 15:20:36 +03:00
map - > s_type_specific . s_sparing . s_packet_len =
le16_to_cpu ( spm - > packetLength ) ;
2007-07-19 12:47:43 +04:00
for ( j = 0 ; j < spm - > numSparingTables ; j + + ) {
2008-02-08 15:20:36 +03:00
struct buffer_head * bh2 ;
loc = le32_to_cpu (
spm - > locSparingTable [ j ] ) ;
bh2 = udf_read_tagged ( sb , loc , loc ,
& ident ) ;
map - > s_type_specific . s_sparing .
s_spar_map [ j ] = bh2 ;
2008-02-10 13:33:08 +03:00
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 ;
2005-04-17 02:20:36 +04:00
}
}
2008-02-08 15:20:30 +03:00
map - > s_partition_func = udf_get_pblock_spar15 ;
2008-04-08 22:37:21 +04:00
} 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 ] ) ;
2011-10-10 12:08:07 +04:00
udf_debug ( " Parsing Logical vol part %d type %d id=%s \n " ,
i , type , UDF_ID_METADATA ) ;
2008-04-08 22:37:21 +04:00
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 ) ;
2011-10-24 18:47:48 +04:00
if ( mdm - > flags & 0x01 )
mdata - > s_flags | = MF_DUPLICATE_MD ;
2008-04-08 22:37:21 +04:00
udf_debug ( " Metadata Ident suffix=0x%x \n " ,
2011-10-10 12:08:07 +04:00
le16_to_cpu ( * ( __le16 * )
mdm - > partIdent . identSuffix ) ) ;
2008-04-08 22:37:21 +04:00
udf_debug ( " Metadata part num=%d \n " ,
2011-10-10 12:08:07 +04:00
le16_to_cpu ( mdm - > partitionNum ) ) ;
2008-04-08 22:37:21 +04:00
udf_debug ( " Metadata part alloc unit size=%d \n " ,
2011-10-10 12:08:07 +04:00
le32_to_cpu ( mdm - > allocUnitSize ) ) ;
2008-04-08 22:37:21 +04:00
udf_debug ( " Metadata file loc=%d \n " ,
2011-10-10 12:08:07 +04:00
le32_to_cpu ( mdm - > metadataFileLoc ) ) ;
2008-04-08 22:37:21 +04:00
udf_debug ( " Mirror file loc=%d \n " ,
2011-10-10 12:08:07 +04:00
le32_to_cpu ( mdm - > metadataMirrorFileLoc ) ) ;
2008-04-08 22:37:21 +04:00
udf_debug ( " Bitmap file loc=%d \n " ,
2011-10-10 12:08:07 +04:00
le32_to_cpu ( mdm - > metadataBitmapFileLoc ) ) ;
2011-10-24 18:47:48 +04:00
udf_debug ( " Flags: %d %d \n " ,
mdata - > s_flags , mdm - > flags ) ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:28 +03:00
udf_debug ( " Unknown ident: %s \n " ,
upm2 - > partIdent . ident ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2008-02-08 15:20:30 +03:00
map - > s_volumeseqnum = le16_to_cpu ( upm2 - > volSeqNum ) ;
map - > s_partition_num = le16_to_cpu ( upm2 - > partitionNum ) ;
2005-04-17 02:20:36 +04:00
}
udf_debug ( " Partition (%d:%d) type %d on volume %d \n " ,
2011-10-10 12:08:07 +04:00
i , map - > s_partition_num , type , map - > s_volumeseqnum ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( fileset ) {
2008-10-15 14:28:03 +04:00
struct long_ad * la = ( struct long_ad * ) & ( lvd - > logicalVolContentsUse [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
* fileset = lelb_to_cpu ( la - > extLocation ) ;
2011-10-10 12:08:07 +04:00
udf_debug ( " FileSet found in LogicalVolDesc at block=%d, partition=%d \n " ,
fileset - > logicalBlockNum ,
2007-07-21 15:37:18 +04:00
fileset - > partitionReferenceNum ) ;
2005-04-17 02:20:36 +04:00
}
if ( lvd - > integritySeqExt . extLength )
udf_load_logicalvolint ( sb , leea_to_cpu ( lvd - > integritySeqExt ) ) ;
2007-07-21 15:37:18 +04:00
2008-04-01 18:50:35 +04:00
out_bh :
brelse ( bh ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
/*
* udf_load_logicalvolint
*
*/
2008-10-15 14:28:03 +04:00
static void udf_load_logicalvolint ( struct super_block * sb , struct kernel_extent_ad loc )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
uint16_t ident ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct logicalVolIntegrityDesc * lvid ;
2005-04-17 02:20:36 +04:00
while ( loc . extLength > 0 & &
2007-07-19 12:47:43 +04:00
( bh = udf_read_tagged ( sb , loc . extLocation ,
loc . extLocation , & ident ) ) & &
ident = = TAG_IDENT_LVID ) {
2008-02-08 15:20:30 +03:00
sbi - > s_lvid_bh = bh ;
lvid = ( struct logicalVolIntegrityDesc * ) bh - > b_data ;
2007-07-19 12:47:43 +04:00
2008-02-08 15:20:30 +03:00
if ( lvid - > nextIntegrityExt . extLength )
2008-02-08 15:20:28 +03:00
udf_load_logicalvolint ( sb ,
2008-02-08 15:20:30 +03:00
leea_to_cpu ( lvid - > nextIntegrityExt ) ) ;
2007-07-19 12:47:43 +04:00
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ! = bh )
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
loc . extLength - = sb - > s_blocksize ;
2007-07-19 12:47:43 +04:00
loc . extLocation + + ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ! = bh )
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
}
/*
* udf_process_sequence
*
* PURPOSE
* Process a main / reserve volume descriptor sequence .
*
* PRE - CONDITIONS
* sb Pointer to _locked_ superblock .
* block First block of first extent of the sequence .
* lastblock Lastblock of first extent of the sequence .
*
* HISTORY
* July 1 , 1997 - Andrew E . Mileski
* Written , tested , and released .
*/
2008-03-04 15:03:09 +03:00
static noinline int udf_process_sequence ( struct super_block * sb , long block ,
2008-10-15 14:28:03 +04:00
long lastblock , struct kernel_lb_addr * fileset )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
struct udf_vds_record vds [ VDS_POS_LENGTH ] ;
2008-02-08 15:20:36 +03:00
struct udf_vds_record * curr ;
2005-04-17 02:20:36 +04:00
struct generic_desc * gd ;
struct volDescPtr * vdp ;
2007-07-19 12:47:43 +04:00
int done = 0 ;
2005-04-17 02:20:36 +04:00
uint32_t vdsn ;
uint16_t ident ;
long next_s = 0 , next_e = 0 ;
memset ( vds , 0 , sizeof ( struct udf_vds_record ) * VDS_POS_LENGTH ) ;
2008-04-01 18:50:35 +04:00
/*
* Read the main descriptor sequence and find which descriptors
* are in it .
*/
2007-07-19 12:47:43 +04:00
for ( ; ( ! done & & block < = lastblock ) ; block + + ) {
2005-04-17 02:20:36 +04:00
bh = udf_read_tagged ( sb , block , block , & ident ) ;
2008-04-01 18:50:35 +04:00
if ( ! bh ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb ,
" Block %llu of volume descriptor sequence is corrupted or we could not read it \n " ,
( unsigned long long ) block ) ;
2008-04-01 18:50:35 +04:00
return 1 ;
}
2005-04-17 02:20:36 +04:00
/* Process each descriptor (ISO 13346 3/8.3-8.4) */
gd = ( struct generic_desc * ) bh - > b_data ;
vdsn = le32_to_cpu ( gd - > volDescSeqNum ) ;
2007-07-19 12:47:43 +04:00
switch ( ident ) {
2007-07-21 15:37:18 +04:00
case TAG_IDENT_PVD : /* ISO 13346 3/10.1 */
2008-02-08 15:20:36 +03:00
curr = & vds [ VDS_POS_PRIMARY_VOL_DESC ] ;
if ( vdsn > = curr - > volDescSeqNum ) {
curr - > volDescSeqNum = vdsn ;
curr - > block = block ;
2007-07-19 12:47:43 +04:00
}
break ;
2007-07-21 15:37:18 +04:00
case TAG_IDENT_VDP : /* ISO 13346 3/10.3 */
2008-02-08 15:20:36 +03:00
curr = & vds [ VDS_POS_VOL_DESC_PTR ] ;
if ( vdsn > = curr - > volDescSeqNum ) {
curr - > volDescSeqNum = vdsn ;
curr - > block = block ;
2007-07-19 12:47:43 +04:00
vdp = ( struct volDescPtr * ) bh - > b_data ;
2008-02-08 15:20:36 +03:00
next_s = le32_to_cpu (
vdp - > nextVolDescSeqExt . extLocation ) ;
next_e = le32_to_cpu (
vdp - > nextVolDescSeqExt . extLength ) ;
2007-07-19 12:47:43 +04:00
next_e = next_e > > sb - > s_blocksize_bits ;
next_e + = next_s ;
}
break ;
2007-07-21 15:37:18 +04:00
case TAG_IDENT_IUVD : /* ISO 13346 3/10.4 */
2008-02-08 15:20:36 +03:00
curr = & vds [ VDS_POS_IMP_USE_VOL_DESC ] ;
if ( vdsn > = curr - > volDescSeqNum ) {
curr - > volDescSeqNum = vdsn ;
curr - > block = block ;
2007-07-19 12:47:43 +04:00
}
break ;
2007-07-21 15:37:18 +04:00
case TAG_IDENT_PD : /* ISO 13346 3/10.5 */
2008-02-08 15:20:36 +03:00
curr = & vds [ VDS_POS_PARTITION_DESC ] ;
if ( ! curr - > block )
curr - > block = block ;
2007-07-19 12:47:43 +04:00
break ;
2007-07-21 15:37:18 +04:00
case TAG_IDENT_LVD : /* ISO 13346 3/10.6 */
2008-02-08 15:20:36 +03:00
curr = & vds [ VDS_POS_LOGICAL_VOL_DESC ] ;
if ( vdsn > = curr - > volDescSeqNum ) {
curr - > volDescSeqNum = vdsn ;
curr - > block = block ;
2007-07-19 12:47:43 +04:00
}
break ;
2007-07-21 15:37:18 +04:00
case TAG_IDENT_USD : /* ISO 13346 3/10.8 */
2008-02-08 15:20:36 +03:00
curr = & vds [ VDS_POS_UNALLOC_SPACE_DESC ] ;
if ( vdsn > = curr - > volDescSeqNum ) {
curr - > volDescSeqNum = vdsn ;
curr - > block = block ;
2007-07-19 12:47:43 +04:00
}
break ;
2007-07-21 15:37:18 +04:00
case TAG_IDENT_TD : /* ISO 13346 3/10.9 */
2007-07-19 12:47:43 +04:00
vds [ VDS_POS_TERMINATING_DESC ] . block = block ;
if ( next_e ) {
block = next_s ;
lastblock = next_e ;
next_s = next_e = 0 ;
2008-02-08 15:20:36 +03:00
} else
2007-07-19 12:47:43 +04:00
done = 1 ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-01 18:50:35 +04:00
/*
* Now read interesting descriptors again and process them
* in a suitable order
*/
if ( ! vds [ VDS_POS_PRIMARY_VOL_DESC ] . block ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb , " Primary Volume Descriptor not found! \n " ) ;
2008-04-01 18:50:35 +04:00
return 1 ;
}
if ( udf_load_pvoldesc ( sb , vds [ VDS_POS_PRIMARY_VOL_DESC ] . block ) )
return 1 ;
2008-02-10 13:33:08 +03:00
2008-04-01 18:50:35 +04:00
if ( vds [ VDS_POS_LOGICAL_VOL_DESC ] . block & & udf_load_logicalvol ( sb ,
vds [ VDS_POS_LOGICAL_VOL_DESC ] . block , fileset ) )
return 1 ;
2008-02-10 13:33:08 +03:00
2008-04-01 18:50:35 +04:00
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 ) )
2008-02-10 13:33:08 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2009-03-19 18:21:38 +03:00
static int udf_load_sequence ( struct super_block * sb , struct buffer_head * bh ,
struct kernel_lb_addr * fileset )
2005-04-17 02:20:36 +04:00
{
2009-03-19 18:21:38 +03:00
struct anchorVolDescPtr * anchor ;
long main_s , main_e , reserve_s , reserve_e ;
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
anchor = ( struct anchorVolDescPtr * ) bh - > b_data ;
/* Locate the main sequence */
main_s = le32_to_cpu ( anchor - > mainVolDescSeqExt . extLocation ) ;
main_e = le32_to_cpu ( anchor - > mainVolDescSeqExt . extLength ) ;
main_e = main_e > > sb - > s_blocksize_bits ;
main_e + = main_s ;
/* Locate the reserve sequence */
reserve_s = le32_to_cpu ( anchor - > reserveVolDescSeqExt . extLocation ) ;
reserve_e = le32_to_cpu ( anchor - > reserveVolDescSeqExt . extLength ) ;
reserve_e = reserve_e > > sb - > s_blocksize_bits ;
reserve_e + = reserve_s ;
/* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */
if ( ! udf_process_sequence ( sb , main_s , main_e , fileset ) )
return 1 ;
return ! udf_process_sequence ( sb , reserve_s , reserve_e , fileset ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-19 18:21:38 +03:00
/*
* Check whether there is an anchor block in the given block and
* load Volume Descriptor Sequence if so .
*/
static int udf_check_anchor_block ( struct super_block * sb , sector_t block ,
struct kernel_lb_addr * fileset )
2009-03-11 17:57:47 +03:00
{
2009-03-19 18:21:38 +03:00
struct buffer_head * bh ;
uint16_t ident ;
int ret ;
2009-03-11 17:57:47 +03:00
2009-03-19 18:21:38 +03:00
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_VARCONV ) & &
udf_fixed_to_variable ( block ) > =
sb - > s_bdev - > bd_inode - > i_size > > sb - > s_blocksize_bits )
2009-03-11 17:57:47 +03:00
return 0 ;
2009-03-19 18:21:38 +03:00
bh = udf_read_tagged ( sb , block , block , & ident ) ;
if ( ! bh )
2009-03-11 17:57:47 +03:00
return 0 ;
2009-03-19 18:21:38 +03:00
if ( ident ! = TAG_IDENT_AVDP ) {
brelse ( bh ) ;
2009-03-11 17:57:47 +03:00
return 0 ;
}
2009-03-19 18:21:38 +03:00
ret = udf_load_sequence ( sb , bh , fileset ) ;
brelse ( bh ) ;
return ret ;
2009-03-11 17:57:47 +03:00
}
2009-03-19 18:21:38 +03:00
/* Search for an anchor volume descriptor pointer */
static sector_t udf_scan_anchors ( struct super_block * sb , sector_t lastblock ,
struct kernel_lb_addr * fileset )
2005-04-17 02:20:36 +04:00
{
2009-03-19 18:21:38 +03:00
sector_t last [ 6 ] ;
2008-04-02 18:01:35 +04:00
int i ;
2009-03-19 18:21:38 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
int last_count = 0 ;
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
/* First try user provided anchor */
if ( sbi - > s_anchor ) {
if ( udf_check_anchor_block ( sb , sbi - > s_anchor , fileset ) )
return lastblock ;
}
/*
* according to spec , anchor is in either :
* block 256
* lastblock - 256
* lastblock
* however , if the disc isn ' t closed , it could be 512.
*/
if ( udf_check_anchor_block ( sb , sbi - > s_session + 256 , fileset ) )
return lastblock ;
/*
* The trouble is which block is the last one . Drives often misreport
* this so we try various possibilities .
*/
last [ last_count + + ] = lastblock ;
if ( lastblock > = 1 )
last [ last_count + + ] = lastblock - 1 ;
last [ last_count + + ] = lastblock + 1 ;
if ( lastblock > = 2 )
last [ last_count + + ] = lastblock - 2 ;
if ( lastblock > = 150 )
last [ last_count + + ] = lastblock - 150 ;
if ( lastblock > = 152 )
last [ last_count + + ] = lastblock - 152 ;
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
for ( i = 0 ; i < last_count ; i + + ) {
if ( last [ i ] > = sb - > s_bdev - > bd_inode - > i_size > >
sb - > s_blocksize_bits )
2008-02-08 15:20:46 +03:00
continue ;
2009-03-19 18:21:38 +03:00
if ( udf_check_anchor_block ( sb , last [ i ] , fileset ) )
return last [ i ] ;
if ( last [ i ] < 256 )
2008-02-08 15:20:46 +03:00
continue ;
2009-03-19 18:21:38 +03:00
if ( udf_check_anchor_block ( sb , last [ i ] - 256 , fileset ) )
return last [ i ] ;
}
2008-02-08 15:20:46 +03:00
2009-03-19 18:21:38 +03:00
/* Finally try block 512 in case media is open */
if ( udf_check_anchor_block ( sb , sbi - > s_session + 512 , fileset ) )
return last [ 0 ] ;
return 0 ;
}
2008-02-08 15:20:46 +03:00
2009-03-19 18:21:38 +03:00
/*
* Find an anchor volume descriptor and load Volume Descriptor Sequence from
* area specified by it . The function expects sbi - > s_lastblock to be the last
* block on the media .
*
* Return 1 if ok , 0 if not found .
*
*/
static int udf_find_anchor ( struct super_block * sb ,
struct kernel_lb_addr * fileset )
{
sector_t lastblock ;
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2008-02-08 15:20:46 +03:00
2009-03-19 18:21:38 +03:00
lastblock = udf_scan_anchors ( sb , sbi - > s_last_block , fileset ) ;
if ( lastblock )
goto out ;
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
/* No anchor found? Try VARCONV conversion of block numbers */
UDF_SET_FLAG ( sb , UDF_FLAG_VARCONV ) ;
/* Firstly, we try to not convert number of the last block */
lastblock = udf_scan_anchors ( sb ,
udf_variable_to_fixed ( sbi - > s_last_block ) ,
fileset ) ;
if ( lastblock )
goto out ;
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
/* Secondly, we try with converted number of the last block */
lastblock = udf_scan_anchors ( sb , sbi - > s_last_block , fileset ) ;
if ( ! lastblock ) {
/* VARCONV didn't help. Clear it. */
UDF_CLEAR_FLAG ( sb , UDF_FLAG_VARCONV ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-03-19 18:21:38 +03:00
out :
sbi - > s_last_block = lastblock ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
/*
* Check Volume Structure Descriptor , find Anchor block and load Volume
* Descriptor Sequence
*/
static int udf_load_vrs ( struct super_block * sb , struct udf_options * uopt ,
int silent , struct kernel_lb_addr * fileset )
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
loff_t nsr_off ;
if ( ! sb_set_blocksize ( sb , uopt - > blocksize ) ) {
if ( ! silent )
2011-10-10 12:08:05 +04:00
udf_warn ( sb , " Bad block size \n " ) ;
2009-03-19 18:21:38 +03:00
return 0 ;
}
sbi - > s_last_block = uopt - > lastblock ;
if ( ! uopt - > novrs ) {
/* Check that it is NSR02 compliant */
nsr_off = udf_check_vsd ( sb ) ;
if ( ! nsr_off ) {
if ( ! silent )
2011-10-10 12:08:05 +04:00
udf_warn ( sb , " No VRS found \n " ) ;
2009-03-19 18:21:38 +03:00
return 0 ;
}
if ( nsr_off = = - 1 )
2011-10-10 12:08:07 +04:00
udf_debug ( " Failed to read byte 32768. Assuming open disc. Skipping validity check \n " ) ;
2009-03-19 18:21:38 +03:00
if ( ! sbi - > s_last_block )
sbi - > s_last_block = udf_get_last_block ( sb ) ;
} else {
udf_debug ( " Validity check skipped because of novrs option \n " ) ;
2008-02-08 15:20:46 +03:00
}
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
/* Look for anchor block and load Volume Descriptor Sequence */
sbi - > s_anchor = uopt - > anchor ;
if ( ! udf_find_anchor ( sb , fileset ) ) {
if ( ! silent )
2011-10-10 12:08:05 +04:00
udf_warn ( sb , " No anchor found \n " ) ;
2009-03-19 18:21:38 +03:00
return 0 ;
}
return 1 ;
2005-04-17 02:20:36 +04:00
}
static void udf_open_lvid ( struct super_block * sb )
{
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct buffer_head * bh = sbi - > s_lvid_bh ;
2008-02-10 13:33:08 +03:00
struct logicalVolIntegrityDesc * lvid ;
struct logicalVolIntegrityDescImpUse * lvidiu ;
2009-03-16 20:27:37 +03:00
2008-02-10 13:33:08 +03:00
if ( ! bh )
return ;
2010-10-20 20:49:20 +04:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-10 13:33:08 +03:00
lvid = ( struct logicalVolIntegrityDesc * ) bh - > b_data ;
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 ) ;
2009-03-16 20:27:37 +03:00
lvid - > integrityType = cpu_to_le32 ( LVID_INTEGRITY_TYPE_OPEN ) ;
2008-02-10 13:33:08 +03:00
lvid - > descTag . descCRC = cpu_to_le16 (
2008-10-15 14:28:03 +04:00
crc_itu_t ( 0 , ( char * ) lvid + sizeof ( struct tag ) ,
2008-04-17 11:47:48 +04:00
le16_to_cpu ( lvid - > descTag . descCRCLength ) ) ) ;
2008-02-10 13:33:08 +03:00
lvid - > descTag . tagChecksum = udf_tag_checksum ( & lvid - > descTag ) ;
mark_buffer_dirty ( bh ) ;
2009-03-16 20:27:37 +03:00
sbi - > s_lvid_dirty = 0 ;
2010-10-20 20:49:20 +04:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
}
static void udf_close_lvid ( struct super_block * sb )
{
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct buffer_head * bh = sbi - > s_lvid_bh ;
struct logicalVolIntegrityDesc * lvid ;
2008-02-10 13:33:08 +03:00
struct logicalVolIntegrityDescImpUse * lvidiu ;
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:30 +03:00
if ( ! bh )
return ;
2010-10-20 20:49:20 +04:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-08 15:20:30 +03:00
lvid = ( struct logicalVolIntegrityDesc * ) bh - > b_data ;
2008-02-10 13:33:08 +03:00
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 . descCRC = cpu_to_le16 (
2008-10-15 14:28:03 +04:00
crc_itu_t ( 0 , ( char * ) lvid + sizeof ( struct tag ) ,
2008-04-17 11:47:48 +04:00
le16_to_cpu ( lvid - > descTag . descCRCLength ) ) ) ;
2008-02-10 13:33:08 +03:00
lvid - > descTag . tagChecksum = udf_tag_checksum ( & lvid - > descTag ) ;
2011-12-23 14:53:07 +04:00
/*
* We set buffer uptodate unconditionally here to avoid spurious
* warnings from mark_buffer_dirty ( ) when previous EIO has marked
* the buffer as ! uptodate
*/
set_buffer_uptodate ( bh ) ;
2008-02-10 13:33:08 +03:00
mark_buffer_dirty ( bh ) ;
2009-03-16 20:27:37 +03:00
sbi - > s_lvid_dirty = 0 ;
2010-10-20 20:49:20 +04:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2010-10-20 20:28:46 +04:00
u64 lvid_get_unique_id ( struct super_block * sb )
{
struct buffer_head * bh ;
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct logicalVolIntegrityDesc * lvid ;
struct logicalVolHeaderDesc * lvhd ;
u64 uniqueID ;
u64 ret ;
bh = sbi - > s_lvid_bh ;
if ( ! bh )
return 0 ;
lvid = ( struct logicalVolIntegrityDesc * ) bh - > b_data ;
lvhd = ( struct logicalVolHeaderDesc * ) lvid - > logicalVolContentsUse ;
mutex_lock ( & sbi - > s_alloc_mutex ) ;
ret = uniqueID = le64_to_cpu ( lvhd - > uniqueID ) ;
if ( ! ( + + uniqueID & 0xFFFFFFFF ) )
uniqueID + = 16 ;
lvhd - > uniqueID = cpu_to_le64 ( uniqueID ) ;
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
mark_buffer_dirty ( bh ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:33 +03:00
static void udf_sb_free_bitmap ( struct udf_bitmap * bitmap )
{
int i ;
int nr_groups = bitmap - > s_nr_groups ;
2008-02-08 15:20:36 +03:00
int size = sizeof ( struct udf_bitmap ) + ( sizeof ( struct buffer_head * ) *
nr_groups ) ;
2008-02-08 15:20:33 +03:00
for ( i = 0 ; i < nr_groups ; i + + )
if ( bitmap - > s_block_bitmap [ i ] )
brelse ( bitmap - > s_block_bitmap [ i ] ) ;
if ( size < = PAGE_SIZE )
kfree ( bitmap ) ;
else
vfree ( bitmap ) ;
}
2008-04-01 20:08:51 +04:00
static void udf_free_partition ( struct udf_part_map * map )
{
int i ;
2008-04-08 22:37:21 +04:00
struct udf_meta_data * mdata ;
2008-04-01 20:08:51 +04:00
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 ] ) ;
2008-04-08 22:37:21 +04:00
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 ;
}
2008-04-01 20:08:51 +04:00
}
2005-04-17 02:20:36 +04:00
static int udf_fill_super ( struct super_block * sb , void * options , int silent )
{
int i ;
2009-03-19 18:21:38 +03:00
int ret ;
2007-07-19 12:47:43 +04:00
struct inode * inode = NULL ;
2005-04-17 02:20:36 +04:00
struct udf_options uopt ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr rootdir , fileset ;
2005-04-17 02:20:36 +04:00
struct udf_sb_info * sbi ;
uopt . flags = ( 1 < < UDF_FLAG_USE_AD_IN_ICB ) | ( 1 < < UDF_FLAG_STRICT ) ;
uopt . uid = - 1 ;
uopt . gid = - 1 ;
uopt . umask = 0 ;
2008-12-02 15:40:11 +03:00
uopt . fmode = UDF_INVALID_MODE ;
uopt . dmode = UDF_INVALID_MODE ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
sbi = kzalloc ( sizeof ( struct udf_sb_info ) , GFP_KERNEL ) ;
2010-11-16 20:40:49 +03:00
if ( ! sbi )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
sb - > s_fs_info = sbi ;
2006-03-23 14:00:44 +03:00
mutex_init ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:21:50 +03:00
if ( ! udf_parse_options ( ( char * ) options , & uopt , false ) )
2005-04-17 02:20:36 +04:00
goto error_out ;
if ( uopt . flags & ( 1 < < UDF_FLAG_UTF8 ) & &
2007-07-19 12:47:43 +04:00
uopt . flags & ( 1 < < UDF_FLAG_NLS_MAP ) ) {
2011-10-10 12:08:03 +04:00
udf_err ( sb , " utf8 cannot be combined with iocharset \n " ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
}
# ifdef CONFIG_UDF_NLS
2007-07-19 12:47:43 +04:00
if ( ( uopt . flags & ( 1 < < UDF_FLAG_NLS_MAP ) ) & & ! uopt . nls_map ) {
2005-04-17 02:20:36 +04:00
uopt . nls_map = load_nls_default ( ) ;
if ( ! uopt . nls_map )
uopt . flags & = ~ ( 1 < < UDF_FLAG_NLS_MAP ) ;
else
udf_debug ( " Using default NLS map \n " ) ;
}
# endif
if ( ! ( uopt . flags & ( 1 < < UDF_FLAG_NLS_MAP ) ) )
uopt . flags | = ( 1 < < UDF_FLAG_UTF8 ) ;
fileset . logicalBlockNum = 0xFFFFFFFF ;
fileset . partitionReferenceNum = 0xFFFF ;
2008-02-08 15:20:30 +03:00
sbi - > s_flags = uopt . flags ;
sbi - > s_uid = uopt . uid ;
sbi - > s_gid = uopt . gid ;
sbi - > s_umask = uopt . umask ;
2008-11-16 22:52:19 +03:00
sbi - > s_fmode = uopt . fmode ;
sbi - > s_dmode = uopt . dmode ;
2008-02-08 15:20:30 +03:00
sbi - > s_nls_map = uopt . nls_map ;
2010-10-21 00:17:28 +04:00
rwlock_init ( & sbi - > s_cred_lock ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( uopt . session = = 0xFFFFFFFF )
2008-02-08 15:20:30 +03:00
sbi - > s_session = udf_get_last_session ( sb ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:30 +03:00
sbi - > s_session = uopt . session ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
udf_debug ( " Multi-session=%d \n " , sbi - > s_session ) ;
2005-04-17 02:20:36 +04:00
2009-03-19 18:21:38 +03:00
/* Fill in the rest of the superblock */
sb - > s_op = & udf_sb_ops ;
sb - > s_export_op = & udf_export_ops ;
2010-05-19 15:16:44 +04:00
2009-03-19 18:21:38 +03:00
sb - > s_dirt = 0 ;
sb - > s_magic = UDF_SUPER_MAGIC ;
sb - > s_time_gran = 1000 ;
2009-03-11 17:57:47 +03:00
if ( uopt . flags & ( 1 < < UDF_FLAG_BLOCKSIZE_SET ) ) {
2009-03-19 18:21:38 +03:00
ret = udf_load_vrs ( sb , & uopt , silent , & fileset ) ;
2009-03-11 17:57:47 +03:00
} else {
2009-05-23 01:17:49 +04:00
uopt . blocksize = bdev_logical_block_size ( sb - > s_bdev ) ;
2009-03-19 18:21:38 +03:00
ret = udf_load_vrs ( sb , & uopt , silent , & fileset ) ;
if ( ! ret & & uopt . blocksize ! = UDF_DEFAULT_BLOCKSIZE ) {
2009-03-11 17:57:47 +03:00
if ( ! silent )
2011-10-10 12:08:05 +04:00
pr_notice ( " Rescanning with blocksize %d \n " ,
UDF_DEFAULT_BLOCKSIZE ) ;
2009-03-11 17:57:47 +03:00
uopt . blocksize = UDF_DEFAULT_BLOCKSIZE ;
2009-03-19 18:21:38 +03:00
ret = udf_load_vrs ( sb , & uopt , silent , & fileset ) ;
2009-03-11 17:57:47 +03:00
}
2005-04-17 02:20:36 +04:00
}
2009-03-19 18:21:38 +03:00
if ( ! ret ) {
2011-10-10 12:08:05 +04:00
udf_warn ( sb , " No partition found (1) \n " ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
}
2008-02-08 15:20:30 +03:00
udf_debug ( " Lastblock=%d \n " , sbi - > s_last_block ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ) {
2008-02-08 15:20:36 +03:00
struct logicalVolIntegrityDescImpUse * lvidiu =
udf_sb_lvidiu ( sbi ) ;
2008-02-08 15:20:30 +03:00
uint16_t minUDFReadRev = le16_to_cpu ( lvidiu - > minUDFReadRev ) ;
uint16_t minUDFWriteRev = le16_to_cpu ( lvidiu - > minUDFWriteRev ) ;
2008-02-08 15:20:36 +03:00
/* uint16_t maxUDFWriteRev =
le16_to_cpu ( lvidiu - > maxUDFWriteRev ) ; */
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( minUDFReadRev > UDF_MAX_READ_VERSION ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb , " minUDFReadRev=%x (max is %x) \n " ,
le16_to_cpu ( lvidiu - > minUDFReadRev ) ,
UDF_MAX_READ_VERSION ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
2008-02-08 15:20:36 +03:00
} else if ( minUDFWriteRev > UDF_MAX_WRITE_VERSION )
2005-04-17 02:20:36 +04:00
sb - > s_flags | = MS_RDONLY ;
2008-02-08 15:20:30 +03:00
sbi - > s_udfrev = minUDFWriteRev ;
2005-04-17 02:20:36 +04:00
if ( minUDFReadRev > = UDF_VERS_USE_EXTENDED_FE )
UDF_SET_FLAG ( sb , UDF_FLAG_USE_EXTENDED_FE ) ;
if ( minUDFReadRev > = UDF_VERS_USE_STREAMS )
UDF_SET_FLAG ( sb , UDF_FLAG_USE_STREAMS ) ;
}
2008-02-08 15:20:30 +03:00
if ( ! sbi - > s_partitions ) {
2011-10-10 12:08:05 +04:00
udf_warn ( sb , " No partition found (2) \n " ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
}
2008-02-08 15:20:36 +03:00
if ( sbi - > s_partmaps [ sbi - > s_partition ] . s_partition_flags &
UDF_PART_FLAG_READ_ONLY ) {
2011-10-10 12:08:05 +04:00
pr_notice ( " Partition marked readonly; forcing readonly mount \n " ) ;
2006-09-29 12:59:41 +04:00
sb - > s_flags | = MS_RDONLY ;
2006-10-05 23:17:50 +04:00
}
2006-09-29 12:59:41 +04:00
2007-07-19 12:47:43 +04:00
if ( udf_find_fileset ( sb , & fileset , & rootdir ) ) {
2011-10-10 12:08:05 +04:00
udf_warn ( sb , " No fileset found \n " ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
}
2007-07-19 12:47:43 +04:00
if ( ! silent ) {
2008-10-15 14:28:03 +04:00
struct timestamp ts ;
2008-02-10 13:25:31 +03:00
udf_time_to_disk_stamp ( & ts , sbi - > s_record_time ) ;
2011-10-10 12:08:05 +04:00
udf_info ( " Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x) \n " ,
sbi - > s_volume_ident ,
le16_to_cpu ( ts . year ) , ts . month , ts . day ,
2008-02-10 13:25:31 +03:00
ts . hour , ts . minute , le16_to_cpu ( ts . typeAndTimezone ) ) ;
2005-04-17 02:20:36 +04:00
}
if ( ! ( sb - > s_flags & MS_RDONLY ) )
udf_open_lvid ( sb ) ;
/* Assign the root inode */
/* assign inodes by physical block number */
/* perhaps it's not extensible enough, but for now ... */
2008-10-15 14:29:03 +04:00
inode = udf_iget ( sb , & rootdir ) ;
2007-07-19 12:47:43 +04:00
if ( ! inode ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb , " Error in udf_iget, block=%d, partition=%d \n " ,
2007-07-19 12:47:43 +04:00
rootdir . logicalBlockNum , rootdir . partitionReferenceNum ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
}
/* Allocate a dentry for the root inode */
2012-01-09 07:15:13 +04:00
sb - > s_root = d_make_root ( inode ) ;
2007-07-19 12:47:43 +04:00
if ( ! sb - > s_root ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb , " Couldn't allocate root dentry \n " ) ;
2005-04-17 02:20:36 +04:00
goto error_out ;
}
2007-05-08 11:35:21 +04:00
sb - > s_maxbytes = MAX_LFS_FILESIZE ;
2012-02-06 21:45:27 +04:00
sb - > s_max_links = UDF_MAX_LINKS ;
2005-04-17 02:20:36 +04:00
return 0 ;
2007-07-21 15:37:18 +04:00
error_out :
2008-02-08 15:20:30 +03:00
if ( sbi - > s_vat_inode )
iput ( sbi - > s_vat_inode ) ;
2008-04-01 20:08:51 +04:00
if ( sbi - > s_partitions )
for ( i = 0 ; i < sbi - > s_partitions ; i + + )
udf_free_partition ( & sbi - > s_partmaps [ i ] ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_UDF_NLS
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_NLS_MAP ) )
2008-02-08 15:20:30 +03:00
unload_nls ( sbi - > s_nls_map ) ;
2005-04-17 02:20:36 +04:00
# endif
if ( ! ( sb - > s_flags & MS_RDONLY ) )
udf_close_lvid ( sb ) ;
2008-02-08 15:20:30 +03:00
brelse ( sbi - > s_lvid_bh ) ;
kfree ( sbi - > s_partmaps ) ;
2005-04-17 02:20:36 +04:00
kfree ( sbi ) ;
sb - > s_fs_info = NULL ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2011-10-10 12:08:03 +04:00
void _udf_err ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
2005-04-17 02:20:36 +04:00
{
2011-10-10 12:08:06 +04:00
struct va_format vaf ;
2005-04-17 02:20:36 +04:00
va_list args ;
2011-10-10 12:08:06 +04:00
/* mark sb error */
if ( ! ( sb - > s_flags & MS_RDONLY ) )
2005-04-17 02:20:36 +04:00
sb - > s_dirt = 1 ;
2011-10-10 12:08:06 +04:00
2005-04-17 02:20:36 +04:00
va_start ( args , fmt ) ;
2011-10-10 12:08:06 +04:00
vaf . fmt = fmt ;
vaf . va = & args ;
pr_err ( " error (device %s): %s: %pV " , sb - > s_id , function , & vaf ) ;
2005-04-17 02:20:36 +04:00
va_end ( args ) ;
}
2011-10-10 12:08:04 +04:00
void _udf_warn ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
2005-04-17 02:20:36 +04:00
{
2011-10-10 12:08:06 +04:00
struct va_format vaf ;
2005-04-17 02:20:36 +04:00
va_list args ;
2007-07-19 12:47:43 +04:00
va_start ( args , fmt ) ;
2011-10-10 12:08:06 +04:00
vaf . fmt = fmt ;
vaf . va = & args ;
pr_warn ( " warning (device %s): %s: %pV " , sb - > s_id , function , & vaf ) ;
2005-04-17 02:20:36 +04:00
va_end ( args ) ;
}
2007-07-19 12:47:43 +04:00
static void udf_put_super ( struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
sbi = UDF_SB ( sb ) ;
push BKL down into ->put_super
Move BKL into ->put_super from the only caller. A couple of
filesystems had trivial enough ->put_super (only kfree and NULLing of
s_fs_info + stuff in there) to not get any locking: coda, cramfs, efs,
hugetlbfs, omfs, qnx4, shmem, all others got the full treatment. Most
of them probably don't need it, but I'd rather sort that out individually.
Preferably after all the other BKL pushdowns in that area.
[AV: original used to move lock_super() down as well; these changes are
removed since we don't do lock_super() at all in generic_shutdown_super()
now]
[AV: fuse, btrfs and xfs are known to need no damn BKL, exempt]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2009-05-05 17:40:36 +04:00
2008-02-08 15:20:30 +03:00
if ( sbi - > s_vat_inode )
iput ( sbi - > s_vat_inode ) ;
2008-04-01 20:08:51 +04:00
if ( sbi - > s_partitions )
for ( i = 0 ; i < sbi - > s_partitions ; i + + )
udf_free_partition ( & sbi - > s_partmaps [ i ] ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_UDF_NLS
if ( UDF_QUERY_FLAG ( sb , UDF_FLAG_NLS_MAP ) )
2008-02-08 15:20:30 +03:00
unload_nls ( sbi - > s_nls_map ) ;
2005-04-17 02:20:36 +04:00
# endif
if ( ! ( sb - > s_flags & MS_RDONLY ) )
udf_close_lvid ( sb ) ;
2008-02-08 15:20:30 +03:00
brelse ( sbi - > s_lvid_bh ) ;
kfree ( sbi - > s_partmaps ) ;
2005-04-17 02:20:36 +04:00
kfree ( sb - > s_fs_info ) ;
sb - > s_fs_info = NULL ;
}
2009-03-16 20:27:37 +03:00
static int udf_sync_fs ( struct super_block * sb , int wait )
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
mutex_lock ( & sbi - > s_alloc_mutex ) ;
if ( sbi - > s_lvid_dirty ) {
/*
* Blockdevice will be synced later so we don ' t have to submit
* the buffer for IO
*/
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
sb - > s_dirt = 0 ;
sbi - > s_lvid_dirty = 0 ;
}
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
return 0 ;
}
2007-07-19 12:47:43 +04:00
static int udf_statfs ( struct dentry * dentry , struct kstatfs * buf )
2005-04-17 02:20:36 +04:00
{
2006-06-23 13:02:58 +04:00
struct super_block * sb = dentry - > d_sb ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct logicalVolIntegrityDescImpUse * lvidiu ;
2009-01-19 20:36:55 +03:00
u64 id = huge_encode_dev ( sb - > s_bdev - > bd_dev ) ;
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ! = NULL )
lvidiu = udf_sb_lvidiu ( sbi ) ;
else
lvidiu = NULL ;
2006-06-23 13:02:58 +04:00
2005-04-17 02:20:36 +04:00
buf - > f_type = UDF_SUPER_MAGIC ;
buf - > f_bsize = sb - > s_blocksize ;
2008-02-08 15:20:30 +03:00
buf - > f_blocks = sbi - > s_partmaps [ sbi - > s_partition ] . s_partition_len ;
2005-04-17 02:20:36 +04:00
buf - > f_bfree = udf_count_free ( sb ) ;
buf - > f_bavail = buf - > f_bfree ;
2008-02-08 15:20:30 +03:00
buf - > f_files = ( lvidiu ! = NULL ? ( le32_to_cpu ( lvidiu - > numFiles ) +
le32_to_cpu ( lvidiu - > numDirs ) ) : 0 )
+ buf - > f_bfree ;
2005-04-17 02:20:36 +04:00
buf - > f_ffree = buf - > f_bfree ;
2007-07-19 12:47:43 +04:00
buf - > f_namelen = UDF_NAME_LEN - 2 ;
2009-01-19 20:36:55 +03:00
buf - > f_fsid . val [ 0 ] = ( u32 ) id ;
buf - > f_fsid . val [ 1 ] = ( u32 ) ( id > > 32 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-02-08 15:20:36 +03:00
static unsigned int udf_count_free_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
unsigned int accum = 0 ;
int index ;
int block = 0 , newblock ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr loc ;
2005-04-17 02:20:36 +04:00
uint32_t bytes ;
uint8_t * ptr ;
uint16_t ident ;
struct spaceBitmapDesc * bm ;
loc . logicalBlockNum = bitmap - > s_extPosition ;
2008-02-08 15:20:30 +03:00
loc . partitionReferenceNum = UDF_SB ( sb ) - > s_partition ;
2008-10-15 14:29:03 +04:00
bh = udf_read_ptagged ( sb , & loc , 0 , & ident ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2011-10-10 12:08:05 +04:00
udf_err ( sb , " udf_count_free failed \n " ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2007-07-19 12:47:43 +04:00
} else if ( ident ! = TAG_IDENT_SBD ) {
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2011-10-10 12:08:05 +04:00
udf_err ( sb , " udf_count_free failed \n " ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
bm = ( struct spaceBitmapDesc * ) bh - > b_data ;
bytes = le32_to_cpu ( bm - > numOfBytes ) ;
2007-07-21 15:37:18 +04:00
index = sizeof ( struct spaceBitmapDesc ) ; /* offset in first block only */
ptr = ( uint8_t * ) bh - > b_data ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
while ( bytes > 0 ) {
2008-02-03 00:37:07 +03:00
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 ;
2007-07-19 12:47:43 +04:00
if ( bytes ) {
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2008-10-15 14:29:03 +04:00
newblock = udf_get_lb_pblock ( sb , & loc , + + block ) ;
2005-04-17 02:20:36 +04:00
bh = udf_tread ( sb , newblock ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " read failed \n " ) ;
goto out ;
}
index = 0 ;
2007-07-21 15:37:18 +04:00
ptr = ( uint8_t * ) bh - > b_data ;
2005-04-17 02:20:36 +04:00
}
}
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
return accum ;
}
2008-02-08 15:20:36 +03:00
static unsigned int udf_count_free_table ( struct super_block * sb ,
struct inode * table )
2005-04-17 02:20:36 +04:00
{
unsigned int accum = 0 ;
2007-05-08 11:35:14 +04:00
uint32_t elen ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2005-04-17 02:20:36 +04:00
int8_t etype ;
2007-05-08 11:35:14 +04:00
struct extent_position epos ;
2005-04-17 02:20:36 +04:00
2010-10-21 01:24:12 +04:00
mutex_lock ( & UDF_SB ( sb ) - > s_alloc_mutex ) ;
2008-02-08 15:20:42 +03:00
epos . block = UDF_I ( table ) - > i_location ;
2007-05-08 11:35:14 +04:00
epos . offset = sizeof ( struct unallocSpaceEntry ) ;
epos . bh = NULL ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:28 +03:00
while ( ( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 )
2005-04-17 02:20:36 +04:00
accum + = ( elen > > table - > i_sb - > s_blocksize_bits ) ;
2008-02-08 15:20:28 +03:00
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2010-10-21 01:24:12 +04:00
mutex_unlock ( & UDF_SB ( sb ) - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return accum ;
}
2007-07-19 12:47:43 +04:00
static unsigned int udf_count_free ( struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
unsigned int accum = 0 ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi ;
struct udf_part_map * map ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
sbi = UDF_SB ( sb ) ;
if ( sbi - > s_lvid_bh ) {
2008-02-08 15:20:36 +03:00
struct logicalVolIntegrityDesc * lvid =
( struct logicalVolIntegrityDesc * )
sbi - > s_lvid_bh - > b_data ;
2008-02-08 15:20:30 +03:00
if ( le32_to_cpu ( lvid - > numOfPartitions ) > sbi - > s_partition ) {
2008-02-08 15:20:36 +03:00
accum = le32_to_cpu (
lvid - > freeSpaceTable [ sbi - > s_partition ] ) ;
2005-04-17 02:20:36 +04:00
if ( accum = = 0xFFFFFFFF )
accum = 0 ;
}
}
if ( accum )
return accum ;
2008-02-08 15:20:30 +03:00
map = & sbi - > s_partmaps [ sbi - > s_partition ] ;
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP ) {
2007-07-21 15:37:18 +04:00
accum + = udf_count_free_bitmap ( sb ,
2008-02-08 15:20:30 +03:00
map - > s_uspace . s_bitmap ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:30 +03:00
if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP ) {
2007-07-21 15:37:18 +04:00
accum + = udf_count_free_bitmap ( sb ,
2008-02-08 15:20:30 +03:00
map - > s_fspace . s_bitmap ) ;
2005-04-17 02:20:36 +04:00
}
if ( accum )
return accum ;
2008-02-08 15:20:30 +03:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE ) {
2007-07-21 15:37:18 +04:00
accum + = udf_count_free_table ( sb ,
2008-02-08 15:20:30 +03:00
map - > s_uspace . s_table ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:30 +03:00
if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE ) {
2007-07-21 15:37:18 +04:00
accum + = udf_count_free_table ( sb ,
2008-02-08 15:20:30 +03:00
map - > s_fspace . s_table ) ;
2005-04-17 02:20:36 +04:00
}
return accum ;
}