2017-03-16 22:18:50 -08:00
/* SPDX-License-Identifier: GPL-2.0 */
# ifndef _BCACHEFS_FS_H
# define _BCACHEFS_FS_H
2018-07-17 14:12:42 -04:00
# include "inode.h"
2017-03-16 22:18:50 -08:00
# include "opts.h"
# include "str_hash.h"
# include "quota_types.h"
# include <linux/seqlock.h>
# include <linux/stat.h>
/*
* Two - state lock - can be taken for add or block - both states are shared ,
* like read side of rwsem , but conflict with other state :
*/
struct pagecache_lock {
atomic_long_t v ;
wait_queue_head_t wait ;
} ;
static inline void pagecache_lock_init ( struct pagecache_lock * lock )
{
atomic_long_set ( & lock - > v , 0 ) ;
init_waitqueue_head ( & lock - > wait ) ;
}
void bch2_pagecache_add_put ( struct pagecache_lock * ) ;
void bch2_pagecache_add_get ( struct pagecache_lock * ) ;
void bch2_pagecache_block_put ( struct pagecache_lock * ) ;
void bch2_pagecache_block_get ( struct pagecache_lock * ) ;
struct bch_inode_info {
struct inode v ;
struct mutex ei_update_lock ;
u64 ei_journal_seq ;
u64 ei_quota_reserved ;
unsigned long ei_last_dirtied ;
struct pagecache_lock ei_pagecache_lock ;
struct mutex ei_quota_lock ;
struct bch_qid ei_qid ;
struct bch_hash_info ei_str_hash ;
/* copy of inode in btree: */
struct bch_inode_unpacked ei_inode ;
} ;
# define to_bch_ei(_inode) \
container_of_or_null ( _inode , struct bch_inode_info , v )
2018-12-17 06:11:14 -05:00
static inline int ptrcmp ( void * l , void * r )
{
2019-04-12 04:54:12 -04:00
return cmp_int ( l , r ) ;
2018-12-17 06:11:14 -05:00
}
2019-06-24 18:24:38 -04:00
enum bch_inode_lock_op {
INODE_LOCK = ( 1U < < 0 ) ,
2019-08-16 09:59:56 -04:00
INODE_PAGECACHE_BLOCK = ( 1U < < 1 ) ,
INODE_UPDATE_LOCK = ( 1U < < 2 ) ,
2019-06-24 18:24:38 -04:00
} ;
# define bch2_lock_inodes(_locks, ...) \
2018-12-17 06:11:14 -05:00
do { \
struct bch_inode_info * a [ ] = { NULL , __VA_ARGS__ } ; \
unsigned i ; \
\
2019-06-24 18:24:38 -04:00
bubble_sort ( & a [ 1 ] , ARRAY_SIZE ( a ) - 1 , ptrcmp ) ; \
2018-12-17 06:11:14 -05:00
\
2019-06-24 18:24:38 -04:00
for ( i = 1 ; i < ARRAY_SIZE ( a ) ; i + + ) \
2018-12-17 06:11:14 -05:00
if ( a [ i ] ! = a [ i - 1 ] ) { \
2019-08-16 09:59:56 -04:00
if ( ( _locks ) & INODE_LOCK ) \
2019-06-24 18:24:38 -04:00
down_write_nested ( & a [ i ] - > v . i_rwsem , i ) ; \
2019-08-16 09:59:56 -04:00
if ( ( _locks ) & INODE_PAGECACHE_BLOCK ) \
bch2_pagecache_block_get ( & a [ i ] - > ei_pagecache_lock ) ; \
if ( ( _locks ) & INODE_UPDATE_LOCK ) \
2018-12-17 06:11:14 -05:00
mutex_lock_nested ( & a [ i ] - > ei_update_lock , i ) ; \
} \
} while ( 0 )
2019-06-24 18:24:38 -04:00
# define bch2_unlock_inodes(_locks, ...) \
do { \
struct bch_inode_info * a [ ] = { NULL , __VA_ARGS__ } ; \
unsigned i ; \
\
bubble_sort ( & a [ 1 ] , ARRAY_SIZE ( a ) - 1 , ptrcmp ) ; \
\
for ( i = 1 ; i < ARRAY_SIZE ( a ) ; i + + ) \
if ( a [ i ] ! = a [ i - 1 ] ) { \
2019-08-16 09:59:56 -04:00
if ( ( _locks ) & INODE_LOCK ) \
2019-06-24 18:24:38 -04:00
up_write ( & a [ i ] - > v . i_rwsem ) ; \
2019-08-16 09:59:56 -04:00
if ( ( _locks ) & INODE_PAGECACHE_BLOCK ) \
bch2_pagecache_block_put ( & a [ i ] - > ei_pagecache_lock ) ; \
if ( ( _locks ) & INODE_UPDATE_LOCK ) \
2019-06-24 18:24:38 -04:00
mutex_unlock ( & a [ i ] - > ei_update_lock ) ; \
} \
} while ( 0 )
2018-12-17 06:11:14 -05:00
2017-03-16 22:18:50 -08:00
static inline struct bch_inode_info * file_bch_inode ( struct file * file )
{
return to_bch_ei ( file_inode ( file ) ) ;
}
2018-12-17 05:31:49 -05:00
static inline bool inode_attr_changing ( struct bch_inode_info * dir ,
struct bch_inode_info * inode ,
enum inode_opt_id id )
{
return ! ( inode - > ei_inode . bi_fields_set & ( 1 < < id ) ) & &
bch2_inode_opt_get ( & dir - > ei_inode , id ) ! =
bch2_inode_opt_get ( & inode - > ei_inode , id ) ;
}
static inline bool inode_attrs_changing ( struct bch_inode_info * dir ,
struct bch_inode_info * inode )
{
unsigned id ;
for ( id = 0 ; id < Inode_opt_nr ; id + + )
if ( inode_attr_changing ( dir , inode , id ) )
return true ;
return false ;
}
2017-03-16 22:18:50 -08:00
struct bch_inode_unpacked ;
# ifndef NO_BCACHEFS_FS
2018-12-17 05:43:00 -05:00
int bch2_fs_quota_transfer ( struct bch_fs * ,
struct bch_inode_info * ,
struct bch_qid ,
unsigned ,
enum quota_acct_mode ) ;
2018-12-19 08:43:01 -05:00
static inline int bch2_set_projid ( struct bch_fs * c ,
struct bch_inode_info * inode ,
u32 projid )
{
struct bch_qid qid = inode - > ei_qid ;
qid . q [ QTYP_PRJ ] = projid ;
return bch2_fs_quota_transfer ( c , inode , qid ,
1 < < QTYP_PRJ ,
KEY_TYPE_QUOTA_PREALLOC ) ;
}
2018-12-17 06:11:14 -05:00
struct inode * bch2_vfs_inode_get ( struct bch_fs * , u64 ) ;
2017-03-16 22:18:50 -08:00
/* returns 0 if we want to do the update, or error is passed up */
typedef int ( * inode_set_fn ) ( struct bch_inode_info * ,
struct bch_inode_unpacked * , void * ) ;
void bch2_inode_update_after_write ( struct bch_fs * ,
struct bch_inode_info * ,
struct bch_inode_unpacked * ,
unsigned ) ;
2018-07-17 14:12:42 -04:00
int __must_check bch2_write_inode ( struct bch_fs * , struct bch_inode_info * ,
inode_set_fn , void * , unsigned ) ;
2017-03-16 22:18:50 -08:00
void bch2_vfs_exit ( void ) ;
int bch2_vfs_init ( void ) ;
# else
static inline void bch2_vfs_exit ( void ) { }
static inline int bch2_vfs_init ( void ) { return 0 ; }
# endif /* NO_BCACHEFS_FS */
# endif /* _BCACHEFS_FS_H */