2017-03-17 09:18:50 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "bkey_methods.h"
# include "btree_update.h"
# include "extents.h"
# include "dirent.h"
# include "fs.h"
# include "keylist.h"
# include "str_hash.h"
# include <linux/dcache.h>
unsigned bch2_dirent_name_bytes ( struct bkey_s_c_dirent d )
{
unsigned len = bkey_val_bytes ( d . k ) -
offsetof ( struct bch_dirent , d_name ) ;
2018-08-22 02:42:00 +03:00
return strnlen ( d . v - > d_name , len ) ;
2017-03-17 09:18:50 +03:00
}
static u64 bch2_dirent_hash ( const struct bch_hash_info * info ,
const struct qstr * name )
{
struct bch_str_hash_ctx ctx ;
bch2_str_hash_init ( & ctx , info ) ;
bch2_str_hash_update ( & ctx , info , name - > name , name - > len ) ;
/* [0,2) reserved for dots */
return max_t ( u64 , bch2_str_hash_end ( & ctx , info ) , 2 ) ;
}
static u64 dirent_hash_key ( const struct bch_hash_info * info , const void * key )
{
return bch2_dirent_hash ( info , key ) ;
}
static u64 dirent_hash_bkey ( const struct bch_hash_info * info , struct bkey_s_c k )
{
struct bkey_s_c_dirent d = bkey_s_c_to_dirent ( k ) ;
struct qstr name = QSTR_INIT ( d . v - > d_name , bch2_dirent_name_bytes ( d ) ) ;
return bch2_dirent_hash ( info , & name ) ;
}
static bool dirent_cmp_key ( struct bkey_s_c _l , const void * _r )
{
struct bkey_s_c_dirent l = bkey_s_c_to_dirent ( _l ) ;
int len = bch2_dirent_name_bytes ( l ) ;
const struct qstr * r = _r ;
return len - r - > len ? : memcmp ( l . v - > d_name , r - > name , len ) ;
}
static bool dirent_cmp_bkey ( struct bkey_s_c _l , struct bkey_s_c _r )
{
struct bkey_s_c_dirent l = bkey_s_c_to_dirent ( _l ) ;
struct bkey_s_c_dirent r = bkey_s_c_to_dirent ( _r ) ;
int l_len = bch2_dirent_name_bytes ( l ) ;
int r_len = bch2_dirent_name_bytes ( r ) ;
return l_len - r_len ? : memcmp ( l . v - > d_name , r . v - > d_name , l_len ) ;
}
const struct bch_hash_desc bch2_dirent_hash_desc = {
2021-02-21 03:27:37 +03:00
. btree_id = BTREE_ID_dirents ,
2018-11-01 22:10:01 +03:00
. key_type = KEY_TYPE_dirent ,
2017-03-17 09:18:50 +03:00
. hash_key = dirent_hash_key ,
. hash_bkey = dirent_hash_bkey ,
. cmp_key = dirent_cmp_key ,
. cmp_bkey = dirent_cmp_bkey ,
} ;
const char * bch2_dirent_invalid ( const struct bch_fs * c , struct bkey_s_c k )
{
2018-11-01 22:10:01 +03:00
struct bkey_s_c_dirent d = bkey_s_c_to_dirent ( k ) ;
2017-03-17 09:18:50 +03:00
unsigned len ;
2018-11-01 22:10:01 +03:00
if ( bkey_val_bytes ( k . k ) < sizeof ( struct bch_dirent ) )
return " value too small " ;
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
len = bch2_dirent_name_bytes ( d ) ;
if ( ! len )
return " empty name " ;
2017-03-17 09:18:50 +03:00
2021-04-07 03:11:28 +03:00
if ( bkey_val_u64s ( k . k ) > dirent_val_u64s ( len ) )
2018-11-01 22:10:01 +03:00
return " value too big " ;
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
if ( len > BCH_NAME_MAX )
return " dirent name too big " ;
2017-03-17 09:18:50 +03:00
2021-04-07 03:11:28 +03:00
if ( len = = 1 & & ! memcmp ( d . v - > d_name , " . " , 1 ) )
return " invalid name " ;
if ( len = = 2 & & ! memcmp ( d . v - > d_name , " .. " , 2 ) )
return " invalid name " ;
if ( memchr ( d . v - > d_name , ' / ' , len ) )
return " invalid name " ;
2021-03-16 07:42:25 +03:00
if ( d . v - > d_type ! = DT_SUBVOL & &
le64_to_cpu ( d . v - > d_inum ) = = d . k - > p . inode )
2021-04-07 03:11:28 +03:00
return " dirent points to own directory " ;
2018-11-01 22:10:01 +03:00
return NULL ;
2017-03-17 09:18:50 +03:00
}
2018-11-09 09:24:07 +03:00
void bch2_dirent_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
2017-03-17 09:18:50 +03:00
{
2018-11-01 22:10:01 +03:00
struct bkey_s_c_dirent d = bkey_s_c_to_dirent ( k ) ;
bch_scnmemcpy ( out , d . v - > d_name ,
bch2_dirent_name_bytes ( d ) ) ;
2021-07-13 06:17:15 +03:00
pr_buf ( out , " -> %llu type %s " , d . v - > d_inum ,
2021-03-16 07:42:25 +03:00
d . v - > d_type < BCH_DT_MAX
2021-07-13 06:17:15 +03:00
? bch2_d_types [ d . v - > d_type ]
: " (bad d_type) " ) ;
2017-03-17 09:18:50 +03:00
}
static struct bkey_i_dirent * dirent_create_key ( struct btree_trans * trans ,
u8 type , const struct qstr * name , u64 dst )
{
struct bkey_i_dirent * dirent ;
unsigned u64s = BKEY_U64s + dirent_val_u64s ( name - > len ) ;
if ( name - > len > BCH_NAME_MAX )
return ERR_PTR ( - ENAMETOOLONG ) ;
BUG_ON ( u64s > U8_MAX ) ;
dirent = bch2_trans_kmalloc ( trans , u64s * sizeof ( u64 ) ) ;
if ( IS_ERR ( dirent ) )
return dirent ;
bkey_dirent_init ( & dirent - > k_i ) ;
dirent - > k . u64s = u64s ;
dirent - > v . d_inum = cpu_to_le64 ( dst ) ;
dirent - > v . d_type = type ;
memcpy ( dirent - > v . d_name , name - > name , name - > len ) ;
memset ( dirent - > v . d_name + name - > len , 0 ,
bkey_val_bytes ( & dirent - > k ) -
offsetof ( struct bch_dirent , d_name ) -
name - > len ) ;
EBUG_ON ( bch2_dirent_name_bytes ( dirent_i_to_s_c ( dirent ) ) ! = name - > len ) ;
return dirent ;
}
2019-10-03 01:35:36 +03:00
int bch2_dirent_create ( struct btree_trans * trans ,
u64 dir_inum , const struct bch_hash_info * hash_info ,
u8 type , const struct qstr * name , u64 dst_inum ,
2021-03-03 02:35:30 +03:00
u64 * dir_offset , int flags )
2017-03-17 09:18:50 +03:00
{
struct bkey_i_dirent * dirent ;
int ret ;
dirent = dirent_create_key ( trans , type , name , dst_inum ) ;
ret = PTR_ERR_OR_ZERO ( dirent ) ;
if ( ret )
return ret ;
2021-03-03 02:35:30 +03:00
ret = bch2_hash_set ( trans , bch2_dirent_hash_desc , hash_info ,
dir_inum , & dirent - > k_i , flags ) ;
* dir_offset = dirent - > k . p . offset ;
return ret ;
2017-03-17 09:18:50 +03:00
}
static void dirent_copy_target ( struct bkey_i_dirent * dst ,
struct bkey_s_c_dirent src )
{
dst - > v . d_inum = src . v - > d_inum ;
dst - > v . d_type = src . v - > d_type ;
}
int bch2_dirent_rename ( struct btree_trans * trans ,
2019-10-03 01:35:36 +03:00
u64 src_dir , struct bch_hash_info * src_hash ,
u64 dst_dir , struct bch_hash_info * dst_hash ,
2021-03-03 02:35:30 +03:00
const struct qstr * src_name , u64 * src_inum , u64 * src_offset ,
const struct qstr * dst_name , u64 * dst_inum , u64 * dst_offset ,
2019-10-03 01:35:36 +03:00
enum bch_rename_mode mode )
2017-03-17 09:18:50 +03:00
{
2021-08-30 22:18:31 +03:00
struct btree_iter src_iter = { NULL } ;
struct btree_iter dst_iter = { NULL } ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c old_src , old_dst ;
struct bkey_i_dirent * new_src = NULL , * new_dst = NULL ;
2019-10-03 01:35:36 +03:00
struct bpos dst_pos =
POS ( dst_dir , bch2_dirent_hash ( dst_hash , dst_name ) ) ;
2020-02-26 23:39:46 +03:00
int ret = 0 ;
2017-03-17 09:18:50 +03:00
2019-10-03 01:35:36 +03:00
* src_inum = * dst_inum = 0 ;
2017-03-17 09:18:50 +03:00
/*
* Lookup dst :
*
* Note that in BCH_RENAME mode , we ' re _not_ checking if
* the target already exists - we ' re relying on the VFS
* to do that check for us for correctness :
*/
2021-08-30 22:18:31 +03:00
ret = mode = = BCH_RENAME
? bch2_hash_hole ( trans , & dst_iter , bch2_dirent_hash_desc ,
2019-10-03 01:35:36 +03:00
dst_hash , dst_dir , dst_name )
2021-08-30 22:18:31 +03:00
: bch2_hash_lookup ( trans , & dst_iter , bch2_dirent_hash_desc ,
2019-10-03 01:35:36 +03:00
dst_hash , dst_dir , dst_name ,
2017-03-17 09:18:50 +03:00
BTREE_ITER_INTENT ) ;
2020-02-26 23:39:46 +03:00
if ( ret )
goto out ;
2021-08-30 22:18:31 +03:00
old_dst = bch2_btree_iter_peek_slot ( & dst_iter ) ;
2021-07-25 02:50:40 +03:00
ret = bkey_err ( old_dst ) ;
if ( ret )
goto out ;
2017-03-17 09:18:50 +03:00
2019-10-03 01:35:36 +03:00
if ( mode ! = BCH_RENAME )
* dst_inum = le64_to_cpu ( bkey_s_c_to_dirent ( old_dst ) . v - > d_inum ) ;
2021-05-20 07:09:47 +03:00
if ( mode ! = BCH_RENAME_EXCHANGE )
2021-08-30 22:18:31 +03:00
* src_offset = dst_iter . pos . offset ;
2019-10-03 01:35:36 +03:00
2017-03-17 09:18:50 +03:00
/* Lookup src: */
2021-08-30 22:18:31 +03:00
ret = bch2_hash_lookup ( trans , & src_iter , bch2_dirent_hash_desc ,
src_hash , src_dir , src_name ,
BTREE_ITER_INTENT ) ;
2020-02-26 23:39:46 +03:00
if ( ret )
goto out ;
2021-08-30 22:18:31 +03:00
old_src = bch2_btree_iter_peek_slot ( & src_iter ) ;
2021-07-25 02:50:40 +03:00
ret = bkey_err ( old_src ) ;
if ( ret )
goto out ;
2019-10-03 01:35:36 +03:00
* src_inum = le64_to_cpu ( bkey_s_c_to_dirent ( old_src ) . v - > d_inum ) ;
2017-03-17 09:18:50 +03:00
/* Create new dst key: */
new_dst = dirent_create_key ( trans , 0 , dst_name , 0 ) ;
2020-02-26 23:39:46 +03:00
ret = PTR_ERR_OR_ZERO ( new_dst ) ;
if ( ret )
goto out ;
2017-03-17 09:18:50 +03:00
dirent_copy_target ( new_dst , bkey_s_c_to_dirent ( old_src ) ) ;
2021-08-30 22:18:31 +03:00
new_dst - > k . p = dst_iter . pos ;
2017-03-17 09:18:50 +03:00
/* Create new src key: */
if ( mode = = BCH_RENAME_EXCHANGE ) {
new_src = dirent_create_key ( trans , 0 , src_name , 0 ) ;
2020-02-26 23:39:46 +03:00
ret = PTR_ERR_OR_ZERO ( new_src ) ;
if ( ret )
goto out ;
2017-03-17 09:18:50 +03:00
dirent_copy_target ( new_src , bkey_s_c_to_dirent ( old_dst ) ) ;
2021-08-30 22:18:31 +03:00
new_src - > k . p = src_iter . pos ;
2017-03-17 09:18:50 +03:00
} else {
new_src = bch2_trans_kmalloc ( trans , sizeof ( struct bkey_i ) ) ;
2020-02-26 23:39:46 +03:00
ret = PTR_ERR_OR_ZERO ( new_src ) ;
if ( ret )
goto out ;
2017-03-17 09:18:50 +03:00
bkey_init ( & new_src - > k ) ;
2021-08-30 22:18:31 +03:00
new_src - > k . p = src_iter . pos ;
2017-03-17 09:18:50 +03:00
2021-08-30 22:18:31 +03:00
if ( bkey_cmp ( dst_pos , src_iter . pos ) < = 0 & &
bkey_cmp ( src_iter . pos , dst_iter . pos ) < 0 ) {
2017-03-17 09:18:50 +03:00
/*
* We have a hash collision for the new dst key ,
* and new_src - the key we ' re deleting - is between
* new_dst ' s hashed slot and the slot we ' re going to be
* inserting it into - oops . This will break the hash
* table if we don ' t deal with it :
*/
if ( mode = = BCH_RENAME ) {
/*
* If we ' re not overwriting , we can just insert
* new_dst at the src position :
*/
2021-08-30 22:18:31 +03:00
new_dst - > k . p = src_iter . pos ;
bch2_trans_update ( trans , & src_iter ,
2020-01-01 00:17:42 +03:00
& new_dst - > k_i , 0 ) ;
2021-03-03 02:35:30 +03:00
goto out_set_offset ;
2017-03-17 09:18:50 +03:00
} else {
/* If we're overwriting, we can't insert new_dst
* at a different slot because it has to
* overwrite old_dst - just make sure to use a
* whiteout when deleting src :
*/
2021-02-21 03:09:53 +03:00
new_src - > k . type = KEY_TYPE_hash_whiteout ;
2017-03-17 09:18:50 +03:00
}
} else {
/* Check if we need a whiteout to delete src: */
ret = bch2_hash_needs_whiteout ( trans , bch2_dirent_hash_desc ,
2021-08-30 22:18:31 +03:00
src_hash , & src_iter ) ;
2017-03-17 09:18:50 +03:00
if ( ret < 0 )
2020-02-26 23:39:46 +03:00
goto out ;
2017-03-17 09:18:50 +03:00
if ( ret )
2021-02-21 03:09:53 +03:00
new_src - > k . type = KEY_TYPE_hash_whiteout ;
2017-03-17 09:18:50 +03:00
}
}
2021-08-30 22:18:31 +03:00
bch2_trans_update ( trans , & src_iter , & new_src - > k_i , 0 ) ;
bch2_trans_update ( trans , & dst_iter , & new_dst - > k_i , 0 ) ;
2021-03-03 02:35:30 +03:00
out_set_offset :
2021-05-20 07:09:47 +03:00
if ( mode = = BCH_RENAME_EXCHANGE )
* src_offset = new_src - > k . p . offset ;
2021-03-03 02:35:30 +03:00
* dst_offset = new_dst - > k . p . offset ;
2020-02-26 23:39:46 +03:00
out :
2021-08-30 22:18:31 +03:00
bch2_trans_iter_exit ( trans , & src_iter ) ;
bch2_trans_iter_exit ( trans , & dst_iter ) ;
2020-02-26 23:39:46 +03:00
return ret ;
2017-03-17 09:18:50 +03:00
}
2019-10-03 01:35:36 +03:00
int bch2_dirent_delete_at ( struct btree_trans * trans ,
const struct bch_hash_info * hash_info ,
struct btree_iter * iter )
2017-03-17 09:18:50 +03:00
{
2019-10-03 01:35:36 +03:00
return bch2_hash_delete_at ( trans , bch2_dirent_hash_desc ,
hash_info , iter ) ;
2017-03-17 09:18:50 +03:00
}
2021-08-30 22:18:31 +03:00
int __bch2_dirent_lookup_trans ( struct btree_trans * trans ,
struct btree_iter * iter ,
u64 dir_inum ,
const struct bch_hash_info * hash_info ,
const struct qstr * name , unsigned flags )
2019-10-03 01:35:36 +03:00
{
2021-08-30 22:18:31 +03:00
return bch2_hash_lookup ( trans , iter , bch2_dirent_hash_desc ,
2019-10-05 03:40:47 +03:00
hash_info , dir_inum , name , flags ) ;
2017-03-17 09:18:50 +03:00
}
u64 bch2_dirent_lookup ( struct bch_fs * c , u64 dir_inum ,
const struct bch_hash_info * hash_info ,
const struct qstr * name )
{
struct btree_trans trans ;
2021-08-30 22:18:31 +03:00
struct btree_iter iter ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c k ;
u64 inum = 0 ;
2021-07-25 02:50:40 +03:00
int ret = 0 ;
2017-03-17 09:18:50 +03:00
2019-05-15 17:54:43 +03:00
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2017-03-17 09:18:50 +03:00
2021-08-30 22:18:31 +03:00
ret = __bch2_dirent_lookup_trans ( & trans , & iter , dir_inum ,
hash_info , name , 0 ) ;
2021-07-25 02:50:40 +03:00
if ( ret )
2017-03-17 09:18:50 +03:00
goto out ;
2021-08-30 22:18:31 +03:00
k = bch2_btree_iter_peek_slot ( & iter ) ;
2021-07-25 02:50:40 +03:00
ret = bkey_err ( k ) ;
if ( ret )
goto out ;
2017-03-17 09:18:50 +03:00
inum = le64_to_cpu ( bkey_s_c_to_dirent ( k ) . v - > d_inum ) ;
2021-08-30 22:18:31 +03:00
bch2_trans_iter_exit ( & trans , & iter ) ;
2017-03-17 09:18:50 +03:00
out :
2021-07-25 02:50:40 +03:00
BUG_ON ( ret = = - EINTR ) ;
2017-03-17 09:18:50 +03:00
bch2_trans_exit ( & trans ) ;
return inum ;
}
2019-04-01 00:37:30 +03:00
int bch2_empty_dir_trans ( struct btree_trans * trans , u64 dir_inum )
2017-03-17 09:18:50 +03:00
{
2021-08-30 22:18:31 +03:00
struct btree_iter iter ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c k ;
2019-04-17 22:49:28 +03:00
int ret ;
2019-03-25 22:10:15 +03:00
2021-02-21 03:27:37 +03:00
for_each_btree_key ( trans , iter , BTREE_ID_dirents ,
2019-04-17 22:49:28 +03:00
POS ( dir_inum , 0 ) , 0 , k , ret ) {
2017-03-17 09:18:50 +03:00
if ( k . k - > p . inode > dir_inum )
break ;
2018-11-01 22:10:01 +03:00
if ( k . k - > type = = KEY_TYPE_dirent ) {
2017-03-17 09:18:50 +03:00
ret = - ENOTEMPTY ;
break ;
}
}
2021-08-30 22:18:31 +03:00
bch2_trans_iter_exit ( trans , & iter ) ;
2017-03-17 09:18:50 +03:00
return ret ;
}
2019-10-03 01:35:36 +03:00
int bch2_readdir ( struct bch_fs * c , u64 inum , struct dir_context * ctx )
2019-04-01 00:37:30 +03:00
{
2019-03-25 22:10:15 +03:00
struct btree_trans trans ;
2021-08-30 22:18:31 +03:00
struct btree_iter iter ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c k ;
struct bkey_s_c_dirent dirent ;
2019-04-17 22:49:28 +03:00
int ret ;
2017-03-17 09:18:50 +03:00
2019-05-15 17:54:43 +03:00
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2019-03-25 22:10:15 +03:00
2021-02-21 03:27:37 +03:00
for_each_btree_key ( & trans , iter , BTREE_ID_dirents ,
2019-10-03 01:35:36 +03:00
POS ( inum , ctx - > pos ) , 0 , k , ret ) {
2019-10-09 16:23:30 +03:00
if ( k . k - > p . inode > inum )
break ;
2018-11-01 22:10:01 +03:00
if ( k . k - > type ! = KEY_TYPE_dirent )
2017-03-17 09:18:50 +03:00
continue ;
dirent = bkey_s_c_to_dirent ( k ) ;
/*
* XXX : dir_emit ( ) can fault and block , while we ' re holding
* locks
*/
2019-10-09 16:23:30 +03:00
ctx - > pos = dirent . k - > p . offset ;
if ( ! dir_emit ( ctx , dirent . v - > d_name ,
bch2_dirent_name_bytes ( dirent ) ,
2017-03-17 09:18:50 +03:00
le64_to_cpu ( dirent . v - > d_inum ) ,
dirent . v - > d_type ) )
break ;
2019-10-09 16:23:30 +03:00
ctx - > pos = dirent . k - > p . offset + 1 ;
2017-03-17 09:18:50 +03:00
}
2021-08-30 22:18:31 +03:00
bch2_trans_iter_exit ( & trans , & iter ) ;
2021-03-20 03:29:11 +03:00
2019-04-17 22:49:28 +03:00
ret = bch2_trans_exit ( & trans ) ? : ret ;
2017-03-17 09:18:50 +03:00
2019-04-17 22:49:28 +03:00
return ret ;
2017-03-17 09:18:50 +03:00
}