2005-04-17 02:20:36 +04:00
/*
* linux / fs / hpfs / hpfs_fn . h
*
* Mikulas Patocka ( mikulas @ artax . karlin . mff . cuni . cz ) , 1998 - 1999
*
* function headers
*/
//#define DBG
//#define DEBUG_LOCKS
2014-06-07 01:36:34 +04:00
# ifdef pr_fmt
# undef pr_fmt
# endif
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:42 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <linux/pagemap.h>
# include <linux/buffer_head.h>
# include <linux/slab.h>
2015-06-28 16:16:57 +03:00
# include <linux/sched.h>
# include <linux/blkdev.h>
2011-05-08 22:44:32 +04:00
# include <asm/unaligned.h>
2005-04-17 02:20:36 +04:00
# include "hpfs.h"
# define EIOERROR EIO
# define EFSERROR EPERM
# define EMEMERROR ENOMEM
# define ANODE_ALLOC_FWD 512
# define FNODE_ALLOC_FWD 0
# define ALLOC_FWD_MIN 16
# define ALLOC_FWD_MAX 128
# define ALLOC_M 1
# define FNODE_RD_AHEAD 16
2013-07-04 21:04:01 +04:00
# define ANODE_RD_AHEAD 0
# define DNODE_RD_AHEAD 72
# define COUNT_RD_AHEAD 62
2005-04-17 02:20:36 +04:00
# define FREE_DNODES_ADD 58
# define FREE_DNODES_DEL 29
# define CHKCOND(x,y) if (!(x)) printk y
struct hpfs_inode_info {
loff_t mmu_private ;
ino_t i_parent_dir ; /* (directories) gives fnode of parent dir */
unsigned i_dno ; /* (directories) root dnode */
unsigned i_dpos ; /* (directories) temp for readdir */
unsigned i_dsubdno ; /* (directories) temp for readdir */
unsigned i_file_sec ; /* (files) minimalist cache of alloc info */
unsigned i_disk_sec ; /* (files) minimalist cache of alloc info */
unsigned i_n_secs ; /* (files) minimalist cache of alloc info */
unsigned i_ea_size ; /* size of extended attributes */
unsigned i_ea_mode : 1 ; /* file's permission is stored in ea */
unsigned i_ea_uid : 1 ; /* file's uid is stored in ea */
unsigned i_ea_gid : 1 ; /* file's gid is stored in ea */
unsigned i_dirty : 1 ;
loff_t * * i_rddir_off ;
struct inode vfs_inode ;
} ;
struct hpfs_sb_info {
2011-05-08 22:42:54 +04:00
struct mutex hpfs_mutex ; /* global hpfs lock */
2005-04-17 02:20:36 +04:00
ino_t sb_root ; /* inode number of root dir */
unsigned sb_fs_size ; /* file system size, sectors */
unsigned sb_bitmaps ; /* sector number of bitmap list */
unsigned sb_dirband_start ; /* directory band start sector */
unsigned sb_dirband_size ; /* directory band size, dnodes */
unsigned sb_dmap ; /* sector number of dnode bit map */
unsigned sb_n_free ; /* free blocks for statfs, or -1 */
unsigned sb_n_free_dnodes ; /* free dnodes for statfs, or -1 */
2012-02-08 04:27:53 +04:00
kuid_t sb_uid ; /* uid from mount options */
kgid_t sb_gid ; /* gid from mount options */
2005-04-17 02:20:36 +04:00
umode_t sb_mode ; /* mode from mount options */
unsigned sb_eas : 2 ; /* eas: 0-ignore, 1-ro, 2-rw */
unsigned sb_err : 2 ; /* on errs: 0-cont, 1-ro, 2-panic */
unsigned sb_chk : 2 ; /* checks: 0-no, 1-normal, 2-strict */
unsigned sb_lowercase : 1 ; /* downcase filenames hackery */
unsigned sb_was_error : 1 ; /* there was an error, set dirty flag */
unsigned sb_chkdsk : 2 ; /* chkdsk: 0-no, 1-on errs, 2-allways */
unsigned char * sb_cp_table ; /* code page tables: */
/* 128 bytes uppercasing table & */
/* 128 bytes lowercasing table */
2012-04-18 00:41:13 +04:00
__le32 * sb_bmp_dir ; /* main bitmap directory */
2005-04-17 02:20:36 +04:00
unsigned sb_c_bitmap ; /* current bitmap */
unsigned sb_max_fwd_alloc ; /* max forwad allocation */
int sb_timeshift ;
2013-10-03 20:25:10 +04:00
struct rcu_head rcu ;
2015-09-02 23:50:12 +03:00
unsigned n_hotfixes ;
secno hotfix_from [ 256 ] ;
secno hotfix_to [ 256 ] ;
2005-04-17 02:20:36 +04:00
} ;
/* Four 512-byte buffers and the 2k block obtained by concatenating them */
struct quad_buffer_head {
struct buffer_head * bh [ 4 ] ;
void * data ;
} ;
/* The b-tree down pointer from a dir entry */
static inline dnode_secno de_down_pointer ( struct hpfs_dirent * de )
{
CHKCOND ( de - > down , ( " HPFS: de_down_pointer: !de->down \n " ) ) ;
2012-04-18 00:20:49 +04:00
return le32_to_cpu ( * ( __le32 * ) ( ( void * ) de + le16_to_cpu ( de - > length ) - 4 ) ) ;
2005-04-17 02:20:36 +04:00
}
/* The first dir entry in a dnode */
static inline struct hpfs_dirent * dnode_first_de ( struct dnode * dnode )
{
return ( void * ) dnode - > dirent ;
}
/* The end+1 of the dir entries */
static inline struct hpfs_dirent * dnode_end_de ( struct dnode * dnode )
{
2011-05-08 22:44:26 +04:00
CHKCOND ( le32_to_cpu ( dnode - > first_free ) > = 0x14 & & le32_to_cpu ( dnode - > first_free ) < = 0xa00 , ( " HPFS: dnode_end_de: dnode->first_free = %x \n " , ( unsigned ) le32_to_cpu ( dnode - > first_free ) ) ) ;
return ( void * ) dnode + le32_to_cpu ( dnode - > first_free ) ;
2005-04-17 02:20:36 +04:00
}
/* The dir entry after dir entry de */
static inline struct hpfs_dirent * de_next_de ( struct hpfs_dirent * de )
{
2011-05-08 22:44:26 +04:00
CHKCOND ( le16_to_cpu ( de - > length ) > = 0x20 & & le16_to_cpu ( de - > length ) < 0x800 , ( " HPFS: de_next_de: de->length = %x \n " , ( unsigned ) le16_to_cpu ( de - > length ) ) ) ;
return ( void * ) de + le16_to_cpu ( de - > length ) ;
2005-04-17 02:20:36 +04:00
}
static inline struct extended_attribute * fnode_ea ( struct fnode * fnode )
{
2011-05-08 22:44:26 +04:00
return ( struct extended_attribute * ) ( ( char * ) fnode + le16_to_cpu ( fnode - > ea_offs ) + le16_to_cpu ( fnode - > acl_size_s ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline struct extended_attribute * fnode_end_ea ( struct fnode * fnode )
{
2011-05-08 22:44:26 +04:00
return ( struct extended_attribute * ) ( ( char * ) fnode + le16_to_cpu ( fnode - > ea_offs ) + le16_to_cpu ( fnode - > acl_size_s ) + le16_to_cpu ( fnode - > ea_size_s ) ) ;
2005-04-17 02:20:36 +04:00
}
2011-05-08 22:44:32 +04:00
static unsigned ea_valuelen ( struct extended_attribute * ea )
{
return ea - > valuelen_lo + 256 * ea - > valuelen_hi ;
}
2005-04-17 02:20:36 +04:00
static inline struct extended_attribute * next_ea ( struct extended_attribute * ea )
{
2011-05-08 22:44:32 +04:00
return ( struct extended_attribute * ) ( ( char * ) ea + 5 + ea - > namelen + ea_valuelen ( ea ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline secno ea_sec ( struct extended_attribute * ea )
{
2012-04-18 00:26:46 +04:00
return le32_to_cpu ( get_unaligned ( ( __le32 * ) ( ( char * ) ea + 9 + ea - > namelen ) ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline secno ea_len ( struct extended_attribute * ea )
{
2012-04-18 00:26:46 +04:00
return le32_to_cpu ( get_unaligned ( ( __le32 * ) ( ( char * ) ea + 5 + ea - > namelen ) ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline char * ea_data ( struct extended_attribute * ea )
{
return ( char * ) ( ( char * ) ea + 5 + ea - > namelen ) ;
}
static inline unsigned de_size ( int namelen , secno down_ptr )
{
return ( ( 0x1f + namelen + 3 ) & ~ 3 ) + ( down_ptr ? 4 : 0 ) ;
}
static inline void copy_de ( struct hpfs_dirent * dst , struct hpfs_dirent * src )
{
int a ;
int n ;
if ( ! dst | | ! src ) return ;
a = dst - > down ;
n = dst - > not_8x3 ;
memcpy ( ( char * ) dst + 2 , ( char * ) src + 2 , 28 ) ;
dst - > down = a ;
dst - > not_8x3 = n ;
}
2012-04-17 23:28:51 +04:00
static inline unsigned tstbits ( __le32 * bmp , unsigned b , unsigned n )
2005-04-17 02:20:36 +04:00
{
int i ;
if ( ( b > = 0x4000 ) | | ( b + n - 1 > = 0x4000 ) ) return n ;
2011-05-08 22:44:26 +04:00
if ( ! ( ( le32_to_cpu ( bmp [ ( b & 0x3fff ) > > 5 ] ) > > ( b & 0x1f ) ) & 1 ) ) return 1 ;
2005-04-17 02:20:36 +04:00
for ( i = 1 ; i < n ; i + + )
2011-05-08 22:44:26 +04:00
if ( ! ( ( le32_to_cpu ( bmp [ ( ( b + i ) & 0x3fff ) > > 5 ] ) > > ( ( b + i ) & 0x1f ) ) & 1 ) )
2005-04-17 02:20:36 +04:00
return i + 1 ;
return 0 ;
}
/* alloc.c */
int hpfs_chk_sectors ( struct super_block * , secno , int , char * ) ;
2011-05-08 22:43:06 +04:00
secno hpfs_alloc_sector ( struct super_block * , secno , unsigned , int ) ;
2005-04-17 02:20:36 +04:00
int hpfs_alloc_if_possible ( struct super_block * , secno ) ;
void hpfs_free_sectors ( struct super_block * , secno , unsigned ) ;
int hpfs_check_free_dnodes ( struct super_block * , int ) ;
void hpfs_free_dnode ( struct super_block * , secno ) ;
2011-05-08 22:43:06 +04:00
struct dnode * hpfs_alloc_dnode ( struct super_block * , secno , dnode_secno * , struct quad_buffer_head * ) ;
2005-04-17 02:20:36 +04:00
struct fnode * hpfs_alloc_fnode ( struct super_block * , secno , fnode_secno * , struct buffer_head * * ) ;
struct anode * hpfs_alloc_anode ( struct super_block * , secno , anode_secno * , struct buffer_head * * ) ;
2015-06-28 16:16:57 +03:00
int hpfs_trim_fs ( struct super_block * , u64 , u64 , u64 , unsigned * ) ;
2005-04-17 02:20:36 +04:00
/* anode.c */
secno hpfs_bplus_lookup ( struct super_block * , struct inode * , struct bplus_header * , unsigned , struct buffer_head * ) ;
secno hpfs_add_sector_to_btree ( struct super_block * , secno , int , unsigned ) ;
void hpfs_remove_btree ( struct super_block * , struct bplus_header * ) ;
int hpfs_ea_read ( struct super_block * , secno , int , unsigned , unsigned , char * ) ;
2010-02-01 01:09:29 +03:00
int hpfs_ea_write ( struct super_block * , secno , int , unsigned , unsigned , const char * ) ;
2005-04-17 02:20:36 +04:00
void hpfs_ea_remove ( struct super_block * , secno , int , unsigned ) ;
void hpfs_truncate_btree ( struct super_block * , secno , int , unsigned ) ;
void hpfs_remove_fnode ( struct super_block * , fnode_secno fno ) ;
/* buffer.c */
2015-09-02 23:50:12 +03:00
secno hpfs_search_hotfix_map ( struct super_block * s , secno sec ) ;
unsigned hpfs_search_hotfix_map_for_range ( struct super_block * s , secno sec , unsigned n ) ;
2013-07-04 21:04:01 +04:00
void hpfs_prefetch_sectors ( struct super_block * , unsigned , int ) ;
2005-04-17 02:20:36 +04:00
void * hpfs_map_sector ( struct super_block * , unsigned , struct buffer_head * * , int ) ;
void * hpfs_get_sector ( struct super_block * , unsigned , struct buffer_head * * ) ;
void * hpfs_map_4sectors ( struct super_block * , unsigned , struct quad_buffer_head * , int ) ;
void * hpfs_get_4sectors ( struct super_block * , unsigned , struct quad_buffer_head * ) ;
void hpfs_brelse4 ( struct quad_buffer_head * ) ;
void hpfs_mark_4buffers_dirty ( struct quad_buffer_head * ) ;
/* dentry.c */
2011-01-13 00:12:05 +03:00
extern const struct dentry_operations hpfs_dentry_operations ;
2005-04-17 02:20:36 +04:00
/* dir.c */
2012-06-11 01:13:09 +04:00
struct dentry * hpfs_lookup ( struct inode * , struct dentry * , unsigned int ) ;
2006-03-28 13:56:42 +04:00
extern const struct file_operations hpfs_dir_ops ;
2005-04-17 02:20:36 +04:00
/* dnode.c */
2016-05-13 02:35:57 +03:00
int hpfs_add_pos ( struct inode * , loff_t * ) ;
2005-04-17 02:20:36 +04:00
void hpfs_del_pos ( struct inode * , loff_t * ) ;
2010-02-01 01:09:29 +03:00
struct hpfs_dirent * hpfs_add_de ( struct super_block * , struct dnode * ,
const unsigned char * , unsigned , secno ) ;
int hpfs_add_dirent ( struct inode * , const unsigned char * , unsigned ,
2011-05-08 22:43:06 +04:00
struct hpfs_dirent * ) ;
2005-04-17 02:20:36 +04:00
int hpfs_remove_dirent ( struct inode * , dnode_secno , struct hpfs_dirent * , struct quad_buffer_head * , int ) ;
void hpfs_count_dnodes ( struct super_block * , dnode_secno , int * , int * , int * ) ;
dnode_secno hpfs_de_as_down_as_possible ( struct super_block * , dnode_secno dno ) ;
struct hpfs_dirent * map_pos_dirent ( struct inode * , loff_t * , struct quad_buffer_head * ) ;
2010-02-01 01:09:29 +03:00
struct hpfs_dirent * map_dirent ( struct inode * , dnode_secno ,
const unsigned char * , unsigned , dnode_secno * ,
struct quad_buffer_head * ) ;
2005-04-17 02:20:36 +04:00
void hpfs_remove_dtree ( struct super_block * , dnode_secno ) ;
struct hpfs_dirent * map_fnode_dirent ( struct super_block * , fnode_secno , struct fnode * , struct quad_buffer_head * ) ;
/* ea.c */
void hpfs_ea_ext_remove ( struct super_block * , secno , int , unsigned ) ;
int hpfs_read_ea ( struct super_block * , struct fnode * , char * , char * , int ) ;
char * hpfs_get_ea ( struct super_block * , struct fnode * , char * , int * ) ;
2010-02-01 01:09:29 +03:00
void hpfs_set_ea ( struct inode * , struct fnode * , const char * ,
const char * , int ) ;
2005-04-17 02:20:36 +04:00
/* file.c */
2011-07-17 04:44:56 +04:00
int hpfs_file_fsync ( struct file * , loff_t , loff_t , int ) ;
2012-12-15 14:53:50 +04:00
void hpfs_truncate ( struct inode * ) ;
2006-03-28 13:56:42 +04:00
extern const struct file_operations hpfs_file_ops ;
2007-02-12 11:55:39 +03:00
extern const struct inode_operations hpfs_file_iops ;
2006-06-28 15:26:44 +04:00
extern const struct address_space_operations hpfs_aops ;
2005-04-17 02:20:36 +04:00
/* inode.c */
void hpfs_init_inode ( struct inode * ) ;
void hpfs_read_inode ( struct inode * ) ;
void hpfs_write_inode ( struct inode * ) ;
void hpfs_write_inode_nolock ( struct inode * ) ;
2008-08-11 02:27:59 +04:00
int hpfs_setattr ( struct dentry * , struct iattr * ) ;
2005-04-17 02:20:36 +04:00
void hpfs_write_if_changed ( struct inode * ) ;
2010-06-07 08:18:40 +04:00
void hpfs_evict_inode ( struct inode * ) ;
2005-04-17 02:20:36 +04:00
/* map.c */
2012-04-17 23:28:51 +04:00
__le32 * hpfs_map_dnode_bitmap ( struct super_block * , struct quad_buffer_head * ) ;
__le32 * hpfs_map_bitmap ( struct super_block * , unsigned , struct quad_buffer_head * , char * ) ;
2013-07-04 21:04:01 +04:00
void hpfs_prefetch_bitmap ( struct super_block * , unsigned ) ;
2010-02-01 01:09:29 +03:00
unsigned char * hpfs_load_code_page ( struct super_block * , secno ) ;
2012-04-18 00:41:13 +04:00
__le32 * hpfs_load_bitmap_directory ( struct super_block * , secno bmp ) ;
2015-09-02 23:50:12 +03:00
void hpfs_load_hotfix_map ( struct super_block * s , struct hpfs_spare_block * spareblock ) ;
2005-04-17 02:20:36 +04:00
struct fnode * hpfs_map_fnode ( struct super_block * s , ino_t , struct buffer_head * * ) ;
struct anode * hpfs_map_anode ( struct super_block * s , anode_secno , struct buffer_head * * ) ;
struct dnode * hpfs_map_dnode ( struct super_block * s , dnode_secno , struct quad_buffer_head * ) ;
dnode_secno hpfs_fnode_dno ( struct super_block * s , ino_t ino ) ;
/* name.c */
unsigned char hpfs_upcase ( unsigned char * , unsigned char ) ;
2010-02-01 01:09:29 +03:00
int hpfs_chk_name ( const unsigned char * , unsigned * ) ;
unsigned char * hpfs_translate_name ( struct super_block * , unsigned char * , unsigned , int , int ) ;
int hpfs_compare_names ( struct super_block * , const unsigned char * , unsigned ,
const unsigned char * , unsigned , int ) ;
int hpfs_is_name_long ( const unsigned char * , unsigned ) ;
void hpfs_adjust_length ( const unsigned char * , unsigned * ) ;
2005-04-17 02:20:36 +04:00
/* namei.c */
2007-02-12 11:55:39 +03:00
extern const struct inode_operations hpfs_dir_iops ;
2006-06-28 15:26:44 +04:00
extern const struct address_space_operations hpfs_symlink_aops ;
2005-04-17 02:20:36 +04:00
static inline struct hpfs_inode_info * hpfs_i ( struct inode * inode )
{
2015-03-19 14:28:04 +03:00
return container_of ( inode , struct hpfs_inode_info , vfs_inode ) ;
2005-04-17 02:20:36 +04:00
}
static inline struct hpfs_sb_info * hpfs_sb ( struct super_block * sb )
{
return sb - > s_fs_info ;
}
/* super.c */
2011-11-01 04:11:33 +04:00
__printf ( 2 , 3 )
void hpfs_error ( struct super_block * , const char * , . . . ) ;
2005-04-17 02:20:36 +04:00
int hpfs_stop_cycles ( struct super_block * , int , int * , int * , char * ) ;
2014-01-29 03:10:44 +04:00
unsigned hpfs_get_free_dnodes ( struct super_block * ) ;
2015-06-28 16:16:57 +03:00
long hpfs_ioctl ( struct file * file , unsigned cmd , unsigned long arg ) ;
2005-04-17 02:20:36 +04:00
/*
* local time ( HPFS ) to GMT ( Unix )
*/
static inline time_t local_to_gmt ( struct super_block * s , time32_t t )
{
extern struct timezone sys_tz ;
return t + sys_tz . tz_minuteswest * 60 + hpfs_sb ( s ) - > sb_timeshift ;
}
static inline time32_t gmt_to_local ( struct super_block * s , time_t t )
{
extern struct timezone sys_tz ;
return t - sys_tz . tz_minuteswest * 60 - hpfs_sb ( s ) - > sb_timeshift ;
}
2011-01-22 22:26:12 +03:00
/*
* Locking :
*
2011-05-08 22:42:54 +04:00
* hpfs_lock ( ) locks the whole filesystem . It must be taken
* on any method called by the VFS .
2011-01-22 22:26:12 +03:00
*
2011-05-08 22:42:54 +04:00
* We don ' t do any per - file locking anymore , it is hard to
* review and HPFS is not performance - sensitive anyway .
2011-01-22 22:26:12 +03:00
*/
static inline void hpfs_lock ( struct super_block * s )
{
2011-05-08 22:42:54 +04:00
struct hpfs_sb_info * sbi = hpfs_sb ( s ) ;
mutex_lock ( & sbi - > hpfs_mutex ) ;
2011-01-22 22:26:12 +03:00
}
static inline void hpfs_unlock ( struct super_block * s )
{
2011-05-08 22:42:54 +04:00
struct hpfs_sb_info * sbi = hpfs_sb ( s ) ;
mutex_unlock ( & sbi - > hpfs_mutex ) ;
}
static inline void hpfs_lock_assert ( struct super_block * s )
{
struct hpfs_sb_info * sbi = hpfs_sb ( s ) ;
WARN_ON ( ! mutex_is_locked ( & sbi - > hpfs_mutex ) ) ;
2011-01-22 22:26:12 +03:00
}