2005-04-17 02:20:36 +04:00
/*
* ialloc . c
*
* PURPOSE
* Inode allocation handling routines for the OSTA - UDF ( tm ) filesystem .
*
* 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 - 2001 Ben Fennema
*
* HISTORY
*
* 02 / 24 / 99 blf Created .
*
*/
# include "udfdecl.h"
# include <linux/fs.h>
# include <linux/quotaops.h>
# include <linux/udf_fs.h>
# include <linux/sched.h>
# include <linux/slab.h>
# include "udf_i.h"
# include "udf_sb.h"
2007-07-19 12:47:43 +04:00
void udf_free_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb = inode - > i_sb ;
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
/*
* Note : we must free any quota before locking the superblock ,
* as writing the quota to disk may need the lock as well .
*/
DQUOT_FREE_INODE ( inode ) ;
DQUOT_DROP ( inode ) ;
clear_inode ( inode ) ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ) {
struct logicalVolIntegrityDescImpUse * lvidiu =
udf_sb_lvidiu ( sbi ) ;
2005-04-17 02:20:36 +04:00
if ( S_ISDIR ( inode - > i_mode ) )
2008-02-08 15:20:30 +03:00
lvidiu - > numDirs =
cpu_to_le32 ( le32_to_cpu ( lvidiu - > numDirs ) - 1 ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:30 +03:00
lvidiu - > numFiles =
cpu_to_le32 ( le32_to_cpu ( lvidiu - > numFiles ) - 1 ) ;
2007-07-16 10:39:43 +04:00
2008-02-08 15:20:30 +03:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:42 +03:00
udf_free_blocks ( sb , NULL , UDF_I ( inode ) - > i_location , 0 , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
struct inode * udf_new_inode ( struct inode * dir , int mode , int * err )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb = dir - > i_sb ;
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2007-07-19 12:47:43 +04:00
struct inode * inode ;
2005-04-17 02:20:36 +04:00
int block ;
2008-02-08 15:20:42 +03:00
uint32_t start = UDF_I ( dir ) - > i_location . logicalBlockNum ;
2005-04-17 02:20:36 +04:00
inode = new_inode ( sb ) ;
2007-07-19 12:47:43 +04:00
if ( ! inode ) {
2005-04-17 02:20:36 +04:00
* err = - ENOMEM ;
return NULL ;
}
* err = - ENOSPC ;
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_unique = 0 ;
UDF_I ( inode ) - > i_lenExtents = 0 ;
UDF_I ( inode ) - > i_next_alloc_block = 0 ;
UDF_I ( inode ) - > i_next_alloc_goal = 0 ;
UDF_I ( inode ) - > i_strat4096 = 0 ;
2006-08-05 23:15:17 +04:00
2008-02-08 15:20:36 +03:00
block = udf_new_block ( dir - > i_sb , NULL ,
2008-02-08 15:20:42 +03:00
UDF_I ( dir ) - > i_location . partitionReferenceNum ,
2007-07-21 15:37:18 +04:00
start , err ) ;
2007-07-19 12:47:43 +04:00
if ( * err ) {
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
return NULL ;
}
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-08 15:20:30 +03:00
if ( sbi - > s_lvid_bh ) {
2008-02-08 15:20:36 +03:00
struct logicalVolIntegrityDesc * lvid =
( struct logicalVolIntegrityDesc * )
sbi - > s_lvid_bh - > b_data ;
struct logicalVolIntegrityDescImpUse * lvidiu =
udf_sb_lvidiu ( sbi ) ;
2005-04-17 02:20:36 +04:00
struct logicalVolHeaderDesc * lvhd ;
uint64_t uniqueID ;
2008-02-08 15:20:36 +03:00
lvhd = ( struct logicalVolHeaderDesc * )
( lvid - > logicalVolContentsUse ) ;
2005-04-17 02:20:36 +04:00
if ( S_ISDIR ( mode ) )
2008-02-08 15:20:30 +03:00
lvidiu - > numDirs =
cpu_to_le32 ( le32_to_cpu ( lvidiu - > numDirs ) + 1 ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:30 +03:00
lvidiu - > numFiles =
cpu_to_le32 ( le32_to_cpu ( lvidiu - > numFiles ) + 1 ) ;
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_unique = uniqueID = le64_to_cpu ( lvhd - > uniqueID ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( + + uniqueID & 0x00000000FFFFFFFFUL ) )
uniqueID + = 16 ;
lvhd - > uniqueID = cpu_to_le64 ( uniqueID ) ;
2008-02-08 15:20:30 +03:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-17 02:20:36 +04:00
}
inode - > i_mode = mode ;
inode - > i_uid = current - > fsuid ;
2007-07-19 12:47:43 +04:00
if ( dir - > i_mode & S_ISGID ) {
2005-04-17 02:20:36 +04:00
inode - > i_gid = dir - > i_gid ;
if ( S_ISDIR ( mode ) )
mode | = S_ISGID ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
inode - > i_gid = current - > fsgid ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_location . logicalBlockNum = block ;
UDF_I ( inode ) - > i_location . partitionReferenceNum =
UDF_I ( dir ) - > i_location . partitionReferenceNum ;
inode - > i_ino = udf_get_lb_pblock ( sb , UDF_I ( inode ) - > i_location , 0 ) ;
2005-04-17 02:20:36 +04:00
inode - > i_blocks = 0 ;
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_lenEAttr = 0 ;
UDF_I ( inode ) - > i_lenAlloc = 0 ;
UDF_I ( inode ) - > i_use = 0 ;
2007-07-19 12:47:43 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_USE_EXTENDED_FE ) ) {
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_efe = 1 ;
2008-02-08 15:20:30 +03:00
if ( UDF_VERS_USE_EXTENDED_FE > sbi - > s_udfrev )
sbi - > s_udfrev = UDF_VERS_USE_EXTENDED_FE ;
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_ext . i_data = kzalloc ( inode - > i_sb - > s_blocksize -
2008-02-08 15:20:36 +03:00
sizeof ( struct extendedFileEntry ) ,
GFP_KERNEL ) ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_efe = 0 ;
UDF_I ( inode ) - > i_ext . i_data = kzalloc ( inode - > i_sb - > s_blocksize -
2008-02-08 15:20:36 +03:00
sizeof ( struct fileEntry ) ,
GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:42 +03:00
if ( ! UDF_I ( inode ) - > i_ext . i_data ) {
2007-07-16 10:39:43 +04:00
iput ( inode ) ;
* err = - ENOMEM ;
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
return NULL ;
}
2005-04-17 02:20:36 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_USE_AD_IN_ICB ) )
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_alloc_type = ICBTAG_FLAG_AD_IN_ICB ;
2005-04-17 02:20:36 +04:00
else if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_USE_SHORT_AD ) )
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_alloc_type = ICBTAG_FLAG_AD_SHORT ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_alloc_type = ICBTAG_FLAG_AD_LONG ;
2005-04-17 02:20:36 +04:00
inode - > i_mtime = inode - > i_atime = inode - > i_ctime =
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_crtime = current_fs_time ( inode - > i_sb ) ;
2005-04-17 02:20:36 +04:00
insert_inode_hash ( inode ) ;
mark_inode_dirty ( inode ) ;
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( DQUOT_ALLOC_INODE ( inode ) ) {
2005-04-17 02:20:36 +04:00
DQUOT_DROP ( inode ) ;
inode - > i_flags | = S_NOQUOTA ;
inode - > i_nlink = 0 ;
iput ( inode ) ;
* err = - EDQUOT ;
return NULL ;
}
* err = 0 ;
return inode ;
}