18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*- 38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * dir.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Creates, reads, walks and deletes directory-nodes 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2004 Oracle. All rights reserved. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Portions of this code from linux/fs/ext3/dir.c 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 148c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 158c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise pascal 168c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * from 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * linux/fs/minix/dir.c 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/fs.h> 268c2ecf20Sopenharmony_ci#include <linux/types.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/highmem.h> 298c2ecf20Sopenharmony_ci#include <linux/quotaops.h> 308c2ecf20Sopenharmony_ci#include <linux/sort.h> 318c2ecf20Sopenharmony_ci#include <linux/iversion.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <cluster/masklog.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "ocfs2.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "alloc.h" 388c2ecf20Sopenharmony_ci#include "blockcheck.h" 398c2ecf20Sopenharmony_ci#include "dir.h" 408c2ecf20Sopenharmony_ci#include "dlmglue.h" 418c2ecf20Sopenharmony_ci#include "extent_map.h" 428c2ecf20Sopenharmony_ci#include "file.h" 438c2ecf20Sopenharmony_ci#include "inode.h" 448c2ecf20Sopenharmony_ci#include "journal.h" 458c2ecf20Sopenharmony_ci#include "namei.h" 468c2ecf20Sopenharmony_ci#include "suballoc.h" 478c2ecf20Sopenharmony_ci#include "super.h" 488c2ecf20Sopenharmony_ci#include "sysfile.h" 498c2ecf20Sopenharmony_ci#include "uptodate.h" 508c2ecf20Sopenharmony_ci#include "ocfs2_trace.h" 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include "buffer_head_io.h" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define NAMEI_RA_CHUNKS 2 558c2ecf20Sopenharmony_ci#define NAMEI_RA_BLOCKS 4 568c2ecf20Sopenharmony_ci#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int ocfs2_do_extend_dir(struct super_block *sb, 598c2ecf20Sopenharmony_ci handle_t *handle, 608c2ecf20Sopenharmony_ci struct inode *dir, 618c2ecf20Sopenharmony_ci struct buffer_head *parent_fe_bh, 628c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 638c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac, 648c2ecf20Sopenharmony_ci struct buffer_head **new_bh); 658c2ecf20Sopenharmony_cistatic int ocfs2_dir_indexed(struct inode *inode); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * These are distinct checks because future versions of the file system will 698c2ecf20Sopenharmony_ci * want to have a trailing dirent structure independent of indexing. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistatic int ocfs2_supports_dir_trailer(struct inode *dir) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return ocfs2_meta_ecc(osb) || ocfs2_dir_indexed(dir); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * "new' here refers to the point at which we're creating a new 838c2ecf20Sopenharmony_ci * directory via "mkdir()", but also when we're expanding an inline 848c2ecf20Sopenharmony_ci * directory. In either case, we don't yet have the indexing bit set 858c2ecf20Sopenharmony_ci * on the directory, so the standard checks will fail in when metaecc 868c2ecf20Sopenharmony_ci * is turned off. Only directory-initialization type functions should 878c2ecf20Sopenharmony_ci * use this then. Everything else wants ocfs2_supports_dir_trailer() 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_cistatic int ocfs2_new_dir_wants_trailer(struct inode *dir) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return ocfs2_meta_ecc(osb) || 948c2ecf20Sopenharmony_ci ocfs2_supports_indexed_dirs(osb); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic inline unsigned int ocfs2_dir_trailer_blk_off(struct super_block *sb) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci return sb->s_blocksize - sizeof(struct ocfs2_dir_block_trailer); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define ocfs2_trailer_from_bh(_bh, _sb) ((struct ocfs2_dir_block_trailer *) ((_bh)->b_data + ocfs2_dir_trailer_blk_off((_sb)))) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* XXX ocfs2_block_dqtrailer() is similar but not quite - can we make 1058c2ecf20Sopenharmony_ci * them more consistent? */ 1068c2ecf20Sopenharmony_cistruct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_size(int blocksize, 1078c2ecf20Sopenharmony_ci void *data) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci char *p = data; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci p += blocksize - sizeof(struct ocfs2_dir_block_trailer); 1128c2ecf20Sopenharmony_ci return (struct ocfs2_dir_block_trailer *)p; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * XXX: This is executed once on every dirent. We should consider optimizing 1178c2ecf20Sopenharmony_ci * it. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic int ocfs2_skip_dir_trailer(struct inode *dir, 1208c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de, 1218c2ecf20Sopenharmony_ci unsigned long offset, 1228c2ecf20Sopenharmony_ci unsigned long blklen) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci unsigned long toff = blklen - sizeof(struct ocfs2_dir_block_trailer); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (!ocfs2_supports_dir_trailer(dir)) 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (offset != toff) 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 1; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void ocfs2_init_dir_trailer(struct inode *inode, 1368c2ecf20Sopenharmony_ci struct buffer_head *bh, u16 rec_len) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci trailer = ocfs2_trailer_from_bh(bh, inode->i_sb); 1418c2ecf20Sopenharmony_ci strcpy(trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE); 1428c2ecf20Sopenharmony_ci trailer->db_compat_rec_len = 1438c2ecf20Sopenharmony_ci cpu_to_le16(sizeof(struct ocfs2_dir_block_trailer)); 1448c2ecf20Sopenharmony_ci trailer->db_parent_dinode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); 1458c2ecf20Sopenharmony_ci trailer->db_blkno = cpu_to_le64(bh->b_blocknr); 1468c2ecf20Sopenharmony_ci trailer->db_free_rec_len = cpu_to_le16(rec_len); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci/* 1498c2ecf20Sopenharmony_ci * Link an unindexed block with a dir trailer structure into the index free 1508c2ecf20Sopenharmony_ci * list. This function will modify dirdata_bh, but assumes you've already 1518c2ecf20Sopenharmony_ci * passed it to the journal. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_link_trailer(struct inode *dir, handle_t *handle, 1548c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh, 1558c2ecf20Sopenharmony_ci struct buffer_head *dirdata_bh) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int ret; 1588c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 1598c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh, 1628c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 1638c2ecf20Sopenharmony_ci if (ret) { 1648c2ecf20Sopenharmony_ci mlog_errno(ret); 1658c2ecf20Sopenharmony_ci goto out; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci trailer = ocfs2_trailer_from_bh(dirdata_bh, dir->i_sb); 1688c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci trailer->db_free_next = dx_root->dr_free_blk; 1718c2ecf20Sopenharmony_ci dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_root_bh); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ciout: 1768c2ecf20Sopenharmony_ci return ret; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int ocfs2_free_list_at_root(struct ocfs2_dir_lookup_result *res) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci return res->dl_prev_leaf_bh == NULL; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_civoid ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci brelse(res->dl_dx_root_bh); 1878c2ecf20Sopenharmony_ci brelse(res->dl_leaf_bh); 1888c2ecf20Sopenharmony_ci brelse(res->dl_dx_leaf_bh); 1898c2ecf20Sopenharmony_ci brelse(res->dl_prev_leaf_bh); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int ocfs2_dir_indexed(struct inode *inode) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INDEXED_DIR_FL) 1958c2ecf20Sopenharmony_ci return 1; 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic inline int ocfs2_dx_root_inline(struct ocfs2_dx_root_block *dx_root) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci return dx_root->dr_flags & OCFS2_DX_FLAG_INLINE; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * Hashing code adapted from ext3 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci#define DELTA 0x9E3779B9 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void TEA_transform(__u32 buf[4], __u32 const in[]) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci __u32 sum = 0; 2128c2ecf20Sopenharmony_ci __u32 b0 = buf[0], b1 = buf[1]; 2138c2ecf20Sopenharmony_ci __u32 a = in[0], b = in[1], c = in[2], d = in[3]; 2148c2ecf20Sopenharmony_ci int n = 16; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci do { 2178c2ecf20Sopenharmony_ci sum += DELTA; 2188c2ecf20Sopenharmony_ci b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); 2198c2ecf20Sopenharmony_ci b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); 2208c2ecf20Sopenharmony_ci } while (--n); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci buf[0] += b0; 2238c2ecf20Sopenharmony_ci buf[1] += b1; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void str2hashbuf(const char *msg, int len, __u32 *buf, int num) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci __u32 pad, val; 2298c2ecf20Sopenharmony_ci int i; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci pad = (__u32)len | ((__u32)len << 8); 2328c2ecf20Sopenharmony_ci pad |= pad << 16; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci val = pad; 2358c2ecf20Sopenharmony_ci if (len > num*4) 2368c2ecf20Sopenharmony_ci len = num * 4; 2378c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 2388c2ecf20Sopenharmony_ci if ((i % 4) == 0) 2398c2ecf20Sopenharmony_ci val = pad; 2408c2ecf20Sopenharmony_ci val = msg[i] + (val << 8); 2418c2ecf20Sopenharmony_ci if ((i % 4) == 3) { 2428c2ecf20Sopenharmony_ci *buf++ = val; 2438c2ecf20Sopenharmony_ci val = pad; 2448c2ecf20Sopenharmony_ci num--; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci if (--num >= 0) 2488c2ecf20Sopenharmony_ci *buf++ = val; 2498c2ecf20Sopenharmony_ci while (--num >= 0) 2508c2ecf20Sopenharmony_ci *buf++ = pad; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void ocfs2_dx_dir_name_hash(struct inode *dir, const char *name, int len, 2548c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 2578c2ecf20Sopenharmony_ci const char *p; 2588c2ecf20Sopenharmony_ci __u32 in[8], buf[4]; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* 2618c2ecf20Sopenharmony_ci * XXX: Is this really necessary, if the index is never looked 2628c2ecf20Sopenharmony_ci * at by readdir? Is a hash value of '0' a bad idea? 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci if ((len == 1 && !strncmp(".", name, 1)) || 2658c2ecf20Sopenharmony_ci (len == 2 && !strncmp("..", name, 2))) { 2668c2ecf20Sopenharmony_ci buf[0] = buf[1] = 0; 2678c2ecf20Sopenharmony_ci goto out; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci#ifdef OCFS2_DEBUG_DX_DIRS 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * This makes it very easy to debug indexing problems. We 2738c2ecf20Sopenharmony_ci * should never allow this to be selected without hand editing 2748c2ecf20Sopenharmony_ci * this file though. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci buf[0] = buf[1] = len; 2778c2ecf20Sopenharmony_ci goto out; 2788c2ecf20Sopenharmony_ci#endif 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci memcpy(buf, osb->osb_dx_seed, sizeof(buf)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci p = name; 2838c2ecf20Sopenharmony_ci while (len > 0) { 2848c2ecf20Sopenharmony_ci str2hashbuf(p, len, in, 4); 2858c2ecf20Sopenharmony_ci TEA_transform(buf, in); 2868c2ecf20Sopenharmony_ci len -= 16; 2878c2ecf20Sopenharmony_ci p += 16; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ciout: 2918c2ecf20Sopenharmony_ci hinfo->major_hash = buf[0]; 2928c2ecf20Sopenharmony_ci hinfo->minor_hash = buf[1]; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * bh passed here can be an inode block or a dir data block, depending 2978c2ecf20Sopenharmony_ci * on the inode inline data flag. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic int ocfs2_check_dir_entry(struct inode *dir, 3008c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de, 3018c2ecf20Sopenharmony_ci struct buffer_head *bh, 3028c2ecf20Sopenharmony_ci char *buf, 3038c2ecf20Sopenharmony_ci unsigned int size, 3048c2ecf20Sopenharmony_ci unsigned long offset) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci const char *error_msg = NULL; 3078c2ecf20Sopenharmony_ci const int rlen = le16_to_cpu(de->rec_len); 3088c2ecf20Sopenharmony_ci const unsigned long next_offset = ((char *) de - buf) + rlen; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (unlikely(rlen < OCFS2_DIR_REC_LEN(1))) 3118c2ecf20Sopenharmony_ci error_msg = "rec_len is smaller than minimal"; 3128c2ecf20Sopenharmony_ci else if (unlikely(rlen % 4 != 0)) 3138c2ecf20Sopenharmony_ci error_msg = "rec_len % 4 != 0"; 3148c2ecf20Sopenharmony_ci else if (unlikely(rlen < OCFS2_DIR_REC_LEN(de->name_len))) 3158c2ecf20Sopenharmony_ci error_msg = "rec_len is too small for name_len"; 3168c2ecf20Sopenharmony_ci else if (unlikely(next_offset > size)) 3178c2ecf20Sopenharmony_ci error_msg = "directory entry overrun"; 3188c2ecf20Sopenharmony_ci else if (unlikely(next_offset > size - OCFS2_DIR_REC_LEN(1)) && 3198c2ecf20Sopenharmony_ci next_offset != size) 3208c2ecf20Sopenharmony_ci error_msg = "directory entry too close to end"; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (unlikely(error_msg != NULL)) 3238c2ecf20Sopenharmony_ci mlog(ML_ERROR, "bad entry in directory #%llu: %s - " 3248c2ecf20Sopenharmony_ci "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n", 3258c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg, 3268c2ecf20Sopenharmony_ci offset, (unsigned long long)le64_to_cpu(de->inode), rlen, 3278c2ecf20Sopenharmony_ci de->name_len); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return error_msg == NULL ? 1 : 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic inline int ocfs2_match(int len, 3338c2ecf20Sopenharmony_ci const char * const name, 3348c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci if (len != de->name_len) 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci if (!de->inode) 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci return !memcmp(name, de->name, len); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/* 3448c2ecf20Sopenharmony_ci * Returns 0 if not found, -1 on failure, and 1 on success 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_cistatic inline int ocfs2_search_dirblock(struct buffer_head *bh, 3478c2ecf20Sopenharmony_ci struct inode *dir, 3488c2ecf20Sopenharmony_ci const char *name, int namelen, 3498c2ecf20Sopenharmony_ci unsigned long offset, 3508c2ecf20Sopenharmony_ci char *first_de, 3518c2ecf20Sopenharmony_ci unsigned int bytes, 3528c2ecf20Sopenharmony_ci struct ocfs2_dir_entry **res_dir) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 3558c2ecf20Sopenharmony_ci char *dlimit, *de_buf; 3568c2ecf20Sopenharmony_ci int de_len; 3578c2ecf20Sopenharmony_ci int ret = 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci de_buf = first_de; 3608c2ecf20Sopenharmony_ci dlimit = de_buf + bytes; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci while (de_buf < dlimit - OCFS2_DIR_MEMBER_LEN) { 3638c2ecf20Sopenharmony_ci /* this code is executed quadratically often */ 3648c2ecf20Sopenharmony_ci /* do minimal checking `by hand' */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) de_buf; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (de->name + namelen <= dlimit && 3698c2ecf20Sopenharmony_ci ocfs2_match(namelen, name, de)) { 3708c2ecf20Sopenharmony_ci /* found a match - just to be sure, do a full check */ 3718c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(dir, de, bh, first_de, 3728c2ecf20Sopenharmony_ci bytes, offset)) { 3738c2ecf20Sopenharmony_ci ret = -1; 3748c2ecf20Sopenharmony_ci goto bail; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci *res_dir = de; 3778c2ecf20Sopenharmony_ci ret = 1; 3788c2ecf20Sopenharmony_ci goto bail; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* prevent looping on a bad block */ 3828c2ecf20Sopenharmony_ci de_len = le16_to_cpu(de->rec_len); 3838c2ecf20Sopenharmony_ci if (de_len <= 0) { 3848c2ecf20Sopenharmony_ci ret = -1; 3858c2ecf20Sopenharmony_ci goto bail; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci de_buf += de_len; 3898c2ecf20Sopenharmony_ci offset += de_len; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cibail: 3938c2ecf20Sopenharmony_ci trace_ocfs2_search_dirblock(ret); 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct buffer_head *ocfs2_find_entry_id(const char *name, 3988c2ecf20Sopenharmony_ci int namelen, 3998c2ecf20Sopenharmony_ci struct inode *dir, 4008c2ecf20Sopenharmony_ci struct ocfs2_dir_entry **res_dir) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci int ret, found; 4038c2ecf20Sopenharmony_ci struct buffer_head *di_bh = NULL; 4048c2ecf20Sopenharmony_ci struct ocfs2_dinode *di; 4058c2ecf20Sopenharmony_ci struct ocfs2_inline_data *data; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = ocfs2_read_inode_block(dir, &di_bh); 4088c2ecf20Sopenharmony_ci if (ret) { 4098c2ecf20Sopenharmony_ci mlog_errno(ret); 4108c2ecf20Sopenharmony_ci goto out; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci di = (struct ocfs2_dinode *)di_bh->b_data; 4148c2ecf20Sopenharmony_ci data = &di->id2.i_data; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0, 4178c2ecf20Sopenharmony_ci data->id_data, i_size_read(dir), res_dir); 4188c2ecf20Sopenharmony_ci if (found == 1) 4198c2ecf20Sopenharmony_ci return di_bh; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci brelse(di_bh); 4228c2ecf20Sopenharmony_ciout: 4238c2ecf20Sopenharmony_ci return NULL; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int ocfs2_validate_dir_block(struct super_block *sb, 4278c2ecf20Sopenharmony_ci struct buffer_head *bh) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci int rc; 4308c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer = 4318c2ecf20Sopenharmony_ci ocfs2_trailer_from_bh(bh, sb); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* 4358c2ecf20Sopenharmony_ci * We don't validate dirents here, that's handled 4368c2ecf20Sopenharmony_ci * in-place when the code walks them. 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci trace_ocfs2_validate_dir_block((unsigned long long)bh->b_blocknr); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci BUG_ON(!buffer_uptodate(bh)); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci * If the ecc fails, we return the error but otherwise 4448c2ecf20Sopenharmony_ci * leave the filesystem running. We know any error is 4458c2ecf20Sopenharmony_ci * local to this block. 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * Note that we are safe to call this even if the directory 4488c2ecf20Sopenharmony_ci * doesn't have a trailer. Filesystems without metaecc will do 4498c2ecf20Sopenharmony_ci * nothing, and filesystems with it will have one. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &trailer->db_check); 4528c2ecf20Sopenharmony_ci if (rc) 4538c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Checksum failed for dinode %llu\n", 4548c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return rc; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/* 4608c2ecf20Sopenharmony_ci * Validate a directory trailer. 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * We check the trailer here rather than in ocfs2_validate_dir_block() 4638c2ecf20Sopenharmony_ci * because that function doesn't have the inode to test. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_cistatic int ocfs2_check_dir_trailer(struct inode *dir, struct buffer_head *bh) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int rc = 0; 4688c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci trailer = ocfs2_trailer_from_bh(bh, dir->i_sb); 4718c2ecf20Sopenharmony_ci if (!OCFS2_IS_VALID_DIR_TRAILER(trailer)) { 4728c2ecf20Sopenharmony_ci rc = ocfs2_error(dir->i_sb, 4738c2ecf20Sopenharmony_ci "Invalid dirblock #%llu: signature = %.*s\n", 4748c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr, 7, 4758c2ecf20Sopenharmony_ci trailer->db_signature); 4768c2ecf20Sopenharmony_ci goto out; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci if (le64_to_cpu(trailer->db_blkno) != bh->b_blocknr) { 4798c2ecf20Sopenharmony_ci rc = ocfs2_error(dir->i_sb, 4808c2ecf20Sopenharmony_ci "Directory block #%llu has an invalid db_blkno of %llu\n", 4818c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr, 4828c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(trailer->db_blkno)); 4838c2ecf20Sopenharmony_ci goto out; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci if (le64_to_cpu(trailer->db_parent_dinode) != 4868c2ecf20Sopenharmony_ci OCFS2_I(dir)->ip_blkno) { 4878c2ecf20Sopenharmony_ci rc = ocfs2_error(dir->i_sb, 4888c2ecf20Sopenharmony_ci "Directory block #%llu on dinode #%llu has an invalid parent_dinode of %llu\n", 4898c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr, 4908c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, 4918c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(trailer->db_blkno)); 4928c2ecf20Sopenharmony_ci goto out; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ciout: 4958c2ecf20Sopenharmony_ci return rc; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/* 4998c2ecf20Sopenharmony_ci * This function forces all errors to -EIO for consistency with its 5008c2ecf20Sopenharmony_ci * predecessor, ocfs2_bread(). We haven't audited what returning the 5018c2ecf20Sopenharmony_ci * real error codes would do to callers. We log the real codes with 5028c2ecf20Sopenharmony_ci * mlog_errno() before we squash them. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_cistatic int ocfs2_read_dir_block(struct inode *inode, u64 v_block, 5058c2ecf20Sopenharmony_ci struct buffer_head **bh, int flags) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci int rc = 0; 5088c2ecf20Sopenharmony_ci struct buffer_head *tmp = *bh; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, flags, 5118c2ecf20Sopenharmony_ci ocfs2_validate_dir_block); 5128c2ecf20Sopenharmony_ci if (rc) { 5138c2ecf20Sopenharmony_ci mlog_errno(rc); 5148c2ecf20Sopenharmony_ci goto out; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (!(flags & OCFS2_BH_READAHEAD) && 5188c2ecf20Sopenharmony_ci ocfs2_supports_dir_trailer(inode)) { 5198c2ecf20Sopenharmony_ci rc = ocfs2_check_dir_trailer(inode, tmp); 5208c2ecf20Sopenharmony_ci if (rc) { 5218c2ecf20Sopenharmony_ci if (!*bh) 5228c2ecf20Sopenharmony_ci brelse(tmp); 5238c2ecf20Sopenharmony_ci mlog_errno(rc); 5248c2ecf20Sopenharmony_ci goto out; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* If ocfs2_read_virt_blocks() got us a new bh, pass it up. */ 5298c2ecf20Sopenharmony_ci if (!*bh) 5308c2ecf20Sopenharmony_ci *bh = tmp; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ciout: 5338c2ecf20Sopenharmony_ci return rc ? -EIO : 0; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci/* 5378c2ecf20Sopenharmony_ci * Read the block at 'phys' which belongs to this directory 5388c2ecf20Sopenharmony_ci * inode. This function does no virtual->physical block translation - 5398c2ecf20Sopenharmony_ci * what's passed in is assumed to be a valid directory block. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic int ocfs2_read_dir_block_direct(struct inode *dir, u64 phys, 5428c2ecf20Sopenharmony_ci struct buffer_head **bh) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci int ret; 5458c2ecf20Sopenharmony_ci struct buffer_head *tmp = *bh; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = ocfs2_read_block(INODE_CACHE(dir), phys, &tmp, 5488c2ecf20Sopenharmony_ci ocfs2_validate_dir_block); 5498c2ecf20Sopenharmony_ci if (ret) { 5508c2ecf20Sopenharmony_ci mlog_errno(ret); 5518c2ecf20Sopenharmony_ci goto out; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (ocfs2_supports_dir_trailer(dir)) { 5558c2ecf20Sopenharmony_ci ret = ocfs2_check_dir_trailer(dir, tmp); 5568c2ecf20Sopenharmony_ci if (ret) { 5578c2ecf20Sopenharmony_ci if (!*bh) 5588c2ecf20Sopenharmony_ci brelse(tmp); 5598c2ecf20Sopenharmony_ci mlog_errno(ret); 5608c2ecf20Sopenharmony_ci goto out; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (!ret && !*bh) 5658c2ecf20Sopenharmony_ci *bh = tmp; 5668c2ecf20Sopenharmony_ciout: 5678c2ecf20Sopenharmony_ci return ret; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic int ocfs2_validate_dx_root(struct super_block *sb, 5718c2ecf20Sopenharmony_ci struct buffer_head *bh) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci int ret; 5748c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci BUG_ON(!buffer_uptodate(bh)); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *) bh->b_data; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci ret = ocfs2_validate_meta_ecc(sb, bh->b_data, &dx_root->dr_check); 5818c2ecf20Sopenharmony_ci if (ret) { 5828c2ecf20Sopenharmony_ci mlog(ML_ERROR, 5838c2ecf20Sopenharmony_ci "Checksum failed for dir index root block %llu\n", 5848c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr); 5858c2ecf20Sopenharmony_ci return ret; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) { 5898c2ecf20Sopenharmony_ci ret = ocfs2_error(sb, 5908c2ecf20Sopenharmony_ci "Dir Index Root # %llu has bad signature %.*s\n", 5918c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(dx_root->dr_blkno), 5928c2ecf20Sopenharmony_ci 7, dx_root->dr_signature); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return ret; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int ocfs2_read_dx_root(struct inode *dir, struct ocfs2_dinode *di, 5998c2ecf20Sopenharmony_ci struct buffer_head **dx_root_bh) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci int ret; 6028c2ecf20Sopenharmony_ci u64 blkno = le64_to_cpu(di->i_dx_root); 6038c2ecf20Sopenharmony_ci struct buffer_head *tmp = *dx_root_bh; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci ret = ocfs2_read_block(INODE_CACHE(dir), blkno, &tmp, 6068c2ecf20Sopenharmony_ci ocfs2_validate_dx_root); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* If ocfs2_read_block() got us a new bh, pass it up. */ 6098c2ecf20Sopenharmony_ci if (!ret && !*dx_root_bh) 6108c2ecf20Sopenharmony_ci *dx_root_bh = tmp; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return ret; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int ocfs2_validate_dx_leaf(struct super_block *sb, 6168c2ecf20Sopenharmony_ci struct buffer_head *bh) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci int ret; 6198c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf = (struct ocfs2_dx_leaf *)bh->b_data; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci BUG_ON(!buffer_uptodate(bh)); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ret = ocfs2_validate_meta_ecc(sb, bh->b_data, &dx_leaf->dl_check); 6248c2ecf20Sopenharmony_ci if (ret) { 6258c2ecf20Sopenharmony_ci mlog(ML_ERROR, 6268c2ecf20Sopenharmony_ci "Checksum failed for dir index leaf block %llu\n", 6278c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr); 6288c2ecf20Sopenharmony_ci return ret; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf)) { 6328c2ecf20Sopenharmony_ci ret = ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s\n", 6338c2ecf20Sopenharmony_ci 7, dx_leaf->dl_signature); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return ret; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic int ocfs2_read_dx_leaf(struct inode *dir, u64 blkno, 6408c2ecf20Sopenharmony_ci struct buffer_head **dx_leaf_bh) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci int ret; 6438c2ecf20Sopenharmony_ci struct buffer_head *tmp = *dx_leaf_bh; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci ret = ocfs2_read_block(INODE_CACHE(dir), blkno, &tmp, 6468c2ecf20Sopenharmony_ci ocfs2_validate_dx_leaf); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* If ocfs2_read_block() got us a new bh, pass it up. */ 6498c2ecf20Sopenharmony_ci if (!ret && !*dx_leaf_bh) 6508c2ecf20Sopenharmony_ci *dx_leaf_bh = tmp; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return ret; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci/* 6568c2ecf20Sopenharmony_ci * Read a series of dx_leaf blocks. This expects all buffer_head 6578c2ecf20Sopenharmony_ci * pointers to be NULL on function entry. 6588c2ecf20Sopenharmony_ci */ 6598c2ecf20Sopenharmony_cistatic int ocfs2_read_dx_leaves(struct inode *dir, u64 start, int num, 6608c2ecf20Sopenharmony_ci struct buffer_head **dx_leaf_bhs) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci int ret; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ret = ocfs2_read_blocks(INODE_CACHE(dir), start, num, dx_leaf_bhs, 0, 6658c2ecf20Sopenharmony_ci ocfs2_validate_dx_leaf); 6668c2ecf20Sopenharmony_ci if (ret) 6678c2ecf20Sopenharmony_ci mlog_errno(ret); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return ret; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, 6738c2ecf20Sopenharmony_ci struct inode *dir, 6748c2ecf20Sopenharmony_ci struct ocfs2_dir_entry **res_dir) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct super_block *sb; 6778c2ecf20Sopenharmony_ci struct buffer_head *bh_use[NAMEI_RA_SIZE]; 6788c2ecf20Sopenharmony_ci struct buffer_head *bh, *ret = NULL; 6798c2ecf20Sopenharmony_ci unsigned long start, block, b; 6808c2ecf20Sopenharmony_ci int ra_max = 0; /* Number of bh's in the readahead 6818c2ecf20Sopenharmony_ci buffer, bh_use[] */ 6828c2ecf20Sopenharmony_ci int ra_ptr = 0; /* Current index into readahead 6838c2ecf20Sopenharmony_ci buffer */ 6848c2ecf20Sopenharmony_ci int num = 0; 6858c2ecf20Sopenharmony_ci int nblocks, i; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci sb = dir->i_sb; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci nblocks = i_size_read(dir) >> sb->s_blocksize_bits; 6908c2ecf20Sopenharmony_ci start = OCFS2_I(dir)->ip_dir_start_lookup; 6918c2ecf20Sopenharmony_ci if (start >= nblocks) 6928c2ecf20Sopenharmony_ci start = 0; 6938c2ecf20Sopenharmony_ci block = start; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cirestart: 6968c2ecf20Sopenharmony_ci do { 6978c2ecf20Sopenharmony_ci /* 6988c2ecf20Sopenharmony_ci * We deal with the read-ahead logic here. 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci if (ra_ptr >= ra_max) { 7018c2ecf20Sopenharmony_ci /* Refill the readahead buffer */ 7028c2ecf20Sopenharmony_ci ra_ptr = 0; 7038c2ecf20Sopenharmony_ci b = block; 7048c2ecf20Sopenharmony_ci for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { 7058c2ecf20Sopenharmony_ci /* 7068c2ecf20Sopenharmony_ci * Terminate if we reach the end of the 7078c2ecf20Sopenharmony_ci * directory and must wrap, or if our 7088c2ecf20Sopenharmony_ci * search has finished at this block. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci if (b >= nblocks || (num && block == start)) { 7118c2ecf20Sopenharmony_ci bh_use[ra_max] = NULL; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci num++; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci bh = NULL; 7178c2ecf20Sopenharmony_ci ocfs2_read_dir_block(dir, b++, &bh, 7188c2ecf20Sopenharmony_ci OCFS2_BH_READAHEAD); 7198c2ecf20Sopenharmony_ci bh_use[ra_max] = bh; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci if ((bh = bh_use[ra_ptr++]) == NULL) 7238c2ecf20Sopenharmony_ci goto next; 7248c2ecf20Sopenharmony_ci if (ocfs2_read_dir_block(dir, block, &bh, 0)) { 7258c2ecf20Sopenharmony_ci /* read error, skip block & hope for the best. 7268c2ecf20Sopenharmony_ci * ocfs2_read_dir_block() has released the bh. */ 7278c2ecf20Sopenharmony_ci mlog(ML_ERROR, "reading directory %llu, " 7288c2ecf20Sopenharmony_ci "offset %lu\n", 7298c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, 7308c2ecf20Sopenharmony_ci block); 7318c2ecf20Sopenharmony_ci goto next; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci i = ocfs2_search_dirblock(bh, dir, name, namelen, 7348c2ecf20Sopenharmony_ci block << sb->s_blocksize_bits, 7358c2ecf20Sopenharmony_ci bh->b_data, sb->s_blocksize, 7368c2ecf20Sopenharmony_ci res_dir); 7378c2ecf20Sopenharmony_ci if (i == 1) { 7388c2ecf20Sopenharmony_ci OCFS2_I(dir)->ip_dir_start_lookup = block; 7398c2ecf20Sopenharmony_ci ret = bh; 7408c2ecf20Sopenharmony_ci goto cleanup_and_exit; 7418c2ecf20Sopenharmony_ci } else { 7428c2ecf20Sopenharmony_ci brelse(bh); 7438c2ecf20Sopenharmony_ci if (i < 0) 7448c2ecf20Sopenharmony_ci goto cleanup_and_exit; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci next: 7478c2ecf20Sopenharmony_ci if (++block >= nblocks) 7488c2ecf20Sopenharmony_ci block = 0; 7498c2ecf20Sopenharmony_ci } while (block != start); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* 7528c2ecf20Sopenharmony_ci * If the directory has grown while we were searching, then 7538c2ecf20Sopenharmony_ci * search the last part of the directory before giving up. 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci block = nblocks; 7568c2ecf20Sopenharmony_ci nblocks = i_size_read(dir) >> sb->s_blocksize_bits; 7578c2ecf20Sopenharmony_ci if (block < nblocks) { 7588c2ecf20Sopenharmony_ci start = 0; 7598c2ecf20Sopenharmony_ci goto restart; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cicleanup_and_exit: 7638c2ecf20Sopenharmony_ci /* Clean up the read-ahead blocks */ 7648c2ecf20Sopenharmony_ci for (; ra_ptr < ra_max; ra_ptr++) 7658c2ecf20Sopenharmony_ci brelse(bh_use[ra_ptr]); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci trace_ocfs2_find_entry_el(ret); 7688c2ecf20Sopenharmony_ci return ret; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_lookup_rec(struct inode *inode, 7728c2ecf20Sopenharmony_ci struct ocfs2_extent_list *el, 7738c2ecf20Sopenharmony_ci u32 major_hash, 7748c2ecf20Sopenharmony_ci u32 *ret_cpos, 7758c2ecf20Sopenharmony_ci u64 *ret_phys_blkno, 7768c2ecf20Sopenharmony_ci unsigned int *ret_clen) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci int ret = 0, i, found; 7798c2ecf20Sopenharmony_ci struct buffer_head *eb_bh = NULL; 7808c2ecf20Sopenharmony_ci struct ocfs2_extent_block *eb; 7818c2ecf20Sopenharmony_ci struct ocfs2_extent_rec *rec = NULL; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (el->l_tree_depth) { 7848c2ecf20Sopenharmony_ci ret = ocfs2_find_leaf(INODE_CACHE(inode), el, major_hash, 7858c2ecf20Sopenharmony_ci &eb_bh); 7868c2ecf20Sopenharmony_ci if (ret) { 7878c2ecf20Sopenharmony_ci mlog_errno(ret); 7888c2ecf20Sopenharmony_ci goto out; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci eb = (struct ocfs2_extent_block *) eb_bh->b_data; 7928c2ecf20Sopenharmony_ci el = &eb->h_list; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (el->l_tree_depth) { 7958c2ecf20Sopenharmony_ci ret = ocfs2_error(inode->i_sb, 7968c2ecf20Sopenharmony_ci "Inode %lu has non zero tree depth in btree tree block %llu\n", 7978c2ecf20Sopenharmony_ci inode->i_ino, 7988c2ecf20Sopenharmony_ci (unsigned long long)eb_bh->b_blocknr); 7998c2ecf20Sopenharmony_ci goto out; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci found = 0; 8048c2ecf20Sopenharmony_ci for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) { 8058c2ecf20Sopenharmony_ci rec = &el->l_recs[i]; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (le32_to_cpu(rec->e_cpos) <= major_hash) { 8088c2ecf20Sopenharmony_ci found = 1; 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (!found) { 8148c2ecf20Sopenharmony_ci ret = ocfs2_error(inode->i_sb, 8158c2ecf20Sopenharmony_ci "Inode %lu has bad extent record (%u, %u, 0) in btree\n", 8168c2ecf20Sopenharmony_ci inode->i_ino, 8178c2ecf20Sopenharmony_ci le32_to_cpu(rec->e_cpos), 8188c2ecf20Sopenharmony_ci ocfs2_rec_clusters(el, rec)); 8198c2ecf20Sopenharmony_ci goto out; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (ret_phys_blkno) 8238c2ecf20Sopenharmony_ci *ret_phys_blkno = le64_to_cpu(rec->e_blkno); 8248c2ecf20Sopenharmony_ci if (ret_cpos) 8258c2ecf20Sopenharmony_ci *ret_cpos = le32_to_cpu(rec->e_cpos); 8268c2ecf20Sopenharmony_ci if (ret_clen) 8278c2ecf20Sopenharmony_ci *ret_clen = le16_to_cpu(rec->e_leaf_clusters); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ciout: 8308c2ecf20Sopenharmony_ci brelse(eb_bh); 8318c2ecf20Sopenharmony_ci return ret; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/* 8358c2ecf20Sopenharmony_ci * Returns the block index, from the start of the cluster which this 8368c2ecf20Sopenharmony_ci * hash belongs too. 8378c2ecf20Sopenharmony_ci */ 8388c2ecf20Sopenharmony_cistatic inline unsigned int __ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb, 8398c2ecf20Sopenharmony_ci u32 minor_hash) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci return minor_hash & osb->osb_dx_mask; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic inline unsigned int ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb, 8458c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci return __ocfs2_dx_dir_hash_idx(osb, hinfo->minor_hash); 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_lookup(struct inode *inode, 8518c2ecf20Sopenharmony_ci struct ocfs2_extent_list *el, 8528c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo, 8538c2ecf20Sopenharmony_ci u32 *ret_cpos, 8548c2ecf20Sopenharmony_ci u64 *ret_phys_blkno) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci int ret = 0; 8578c2ecf20Sopenharmony_ci unsigned int cend, clen; 8588c2ecf20Sopenharmony_ci u32 cpos; 8598c2ecf20Sopenharmony_ci u64 blkno; 8608c2ecf20Sopenharmony_ci u32 name_hash = hinfo->major_hash; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_lookup_rec(inode, el, name_hash, &cpos, &blkno, 8638c2ecf20Sopenharmony_ci &clen); 8648c2ecf20Sopenharmony_ci if (ret) { 8658c2ecf20Sopenharmony_ci mlog_errno(ret); 8668c2ecf20Sopenharmony_ci goto out; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci cend = cpos + clen; 8708c2ecf20Sopenharmony_ci if (name_hash >= cend) { 8718c2ecf20Sopenharmony_ci /* We want the last cluster */ 8728c2ecf20Sopenharmony_ci blkno += ocfs2_clusters_to_blocks(inode->i_sb, clen - 1); 8738c2ecf20Sopenharmony_ci cpos += clen - 1; 8748c2ecf20Sopenharmony_ci } else { 8758c2ecf20Sopenharmony_ci blkno += ocfs2_clusters_to_blocks(inode->i_sb, 8768c2ecf20Sopenharmony_ci name_hash - cpos); 8778c2ecf20Sopenharmony_ci cpos = name_hash; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* 8818c2ecf20Sopenharmony_ci * We now have the cluster which should hold our entry. To 8828c2ecf20Sopenharmony_ci * find the exact block from the start of the cluster to 8838c2ecf20Sopenharmony_ci * search, we take the lower bits of the hash. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci blkno += ocfs2_dx_dir_hash_idx(OCFS2_SB(inode->i_sb), hinfo); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (ret_phys_blkno) 8888c2ecf20Sopenharmony_ci *ret_phys_blkno = blkno; 8898c2ecf20Sopenharmony_ci if (ret_cpos) 8908c2ecf20Sopenharmony_ci *ret_cpos = cpos; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ciout: 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_search(const char *name, int namelen, 8988c2ecf20Sopenharmony_ci struct inode *dir, 8998c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root, 9008c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *res) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int ret, i, found; 9038c2ecf20Sopenharmony_ci u64 phys; 9048c2ecf20Sopenharmony_ci struct buffer_head *dx_leaf_bh = NULL; 9058c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf; 9068c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *dx_entry = NULL; 9078c2ecf20Sopenharmony_ci struct buffer_head *dir_ent_bh = NULL; 9088c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *dir_ent = NULL; 9098c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo = &res->dl_hinfo; 9108c2ecf20Sopenharmony_ci struct ocfs2_extent_list *dr_el; 9118c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *entry_list; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (ocfs2_dx_root_inline(dx_root)) { 9168c2ecf20Sopenharmony_ci entry_list = &dx_root->dr_entries; 9178c2ecf20Sopenharmony_ci goto search; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci dr_el = &dx_root->dr_list; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_lookup(dir, dr_el, hinfo, NULL, &phys); 9238c2ecf20Sopenharmony_ci if (ret) { 9248c2ecf20Sopenharmony_ci mlog_errno(ret); 9258c2ecf20Sopenharmony_ci goto out; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_search((unsigned long long)OCFS2_I(dir)->ip_blkno, 9298c2ecf20Sopenharmony_ci namelen, name, hinfo->major_hash, 9308c2ecf20Sopenharmony_ci hinfo->minor_hash, (unsigned long long)phys); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_leaf(dir, phys, &dx_leaf_bh); 9338c2ecf20Sopenharmony_ci if (ret) { 9348c2ecf20Sopenharmony_ci mlog_errno(ret); 9358c2ecf20Sopenharmony_ci goto out; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci dx_leaf = (struct ocfs2_dx_leaf *) dx_leaf_bh->b_data; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_search_leaf_info( 9418c2ecf20Sopenharmony_ci le16_to_cpu(dx_leaf->dl_list.de_num_used), 9428c2ecf20Sopenharmony_ci le16_to_cpu(dx_leaf->dl_list.de_count)); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci entry_list = &dx_leaf->dl_list; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cisearch: 9478c2ecf20Sopenharmony_ci /* 9488c2ecf20Sopenharmony_ci * Empty leaf is legal, so no need to check for that. 9498c2ecf20Sopenharmony_ci */ 9508c2ecf20Sopenharmony_ci found = 0; 9518c2ecf20Sopenharmony_ci for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) { 9528c2ecf20Sopenharmony_ci dx_entry = &entry_list->de_entries[i]; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (hinfo->major_hash != le32_to_cpu(dx_entry->dx_major_hash) 9558c2ecf20Sopenharmony_ci || hinfo->minor_hash != le32_to_cpu(dx_entry->dx_minor_hash)) 9568c2ecf20Sopenharmony_ci continue; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* 9598c2ecf20Sopenharmony_ci * Search unindexed leaf block now. We're not 9608c2ecf20Sopenharmony_ci * guaranteed to find anything. 9618c2ecf20Sopenharmony_ci */ 9628c2ecf20Sopenharmony_ci ret = ocfs2_read_dir_block_direct(dir, 9638c2ecf20Sopenharmony_ci le64_to_cpu(dx_entry->dx_dirent_blk), 9648c2ecf20Sopenharmony_ci &dir_ent_bh); 9658c2ecf20Sopenharmony_ci if (ret) { 9668c2ecf20Sopenharmony_ci mlog_errno(ret); 9678c2ecf20Sopenharmony_ci goto out; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* 9718c2ecf20Sopenharmony_ci * XXX: We should check the unindexed block here, 9728c2ecf20Sopenharmony_ci * before using it. 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci found = ocfs2_search_dirblock(dir_ent_bh, dir, name, namelen, 9768c2ecf20Sopenharmony_ci 0, dir_ent_bh->b_data, 9778c2ecf20Sopenharmony_ci dir->i_sb->s_blocksize, &dir_ent); 9788c2ecf20Sopenharmony_ci if (found == 1) 9798c2ecf20Sopenharmony_ci break; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (found == -1) { 9828c2ecf20Sopenharmony_ci /* This means we found a bad directory entry. */ 9838c2ecf20Sopenharmony_ci ret = -EIO; 9848c2ecf20Sopenharmony_ci mlog_errno(ret); 9858c2ecf20Sopenharmony_ci goto out; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci brelse(dir_ent_bh); 9898c2ecf20Sopenharmony_ci dir_ent_bh = NULL; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (found <= 0) { 9938c2ecf20Sopenharmony_ci ret = -ENOENT; 9948c2ecf20Sopenharmony_ci goto out; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci res->dl_leaf_bh = dir_ent_bh; 9988c2ecf20Sopenharmony_ci res->dl_entry = dir_ent; 9998c2ecf20Sopenharmony_ci res->dl_dx_leaf_bh = dx_leaf_bh; 10008c2ecf20Sopenharmony_ci res->dl_dx_entry = dx_entry; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci ret = 0; 10038c2ecf20Sopenharmony_ciout: 10048c2ecf20Sopenharmony_ci if (ret) { 10058c2ecf20Sopenharmony_ci brelse(dx_leaf_bh); 10068c2ecf20Sopenharmony_ci brelse(dir_ent_bh); 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci return ret; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int ocfs2_find_entry_dx(const char *name, int namelen, 10128c2ecf20Sopenharmony_ci struct inode *dir, 10138c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci int ret; 10168c2ecf20Sopenharmony_ci struct buffer_head *di_bh = NULL; 10178c2ecf20Sopenharmony_ci struct ocfs2_dinode *di; 10188c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 10198c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci ret = ocfs2_read_inode_block(dir, &di_bh); 10228c2ecf20Sopenharmony_ci if (ret) { 10238c2ecf20Sopenharmony_ci mlog_errno(ret); 10248c2ecf20Sopenharmony_ci goto out; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci di = (struct ocfs2_dinode *)di_bh->b_data; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_root(dir, di, &dx_root_bh); 10308c2ecf20Sopenharmony_ci if (ret) { 10318c2ecf20Sopenharmony_ci mlog_errno(ret); 10328c2ecf20Sopenharmony_ci goto out; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_search(name, namelen, dir, dx_root, lookup); 10378c2ecf20Sopenharmony_ci if (ret) { 10388c2ecf20Sopenharmony_ci if (ret != -ENOENT) 10398c2ecf20Sopenharmony_ci mlog_errno(ret); 10408c2ecf20Sopenharmony_ci goto out; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci lookup->dl_dx_root_bh = dx_root_bh; 10448c2ecf20Sopenharmony_ci dx_root_bh = NULL; 10458c2ecf20Sopenharmony_ciout: 10468c2ecf20Sopenharmony_ci brelse(di_bh); 10478c2ecf20Sopenharmony_ci brelse(dx_root_bh); 10488c2ecf20Sopenharmony_ci return ret; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci/* 10528c2ecf20Sopenharmony_ci * Try to find an entry of the provided name within 'dir'. 10538c2ecf20Sopenharmony_ci * 10548c2ecf20Sopenharmony_ci * If nothing was found, -ENOENT is returned. Otherwise, zero is 10558c2ecf20Sopenharmony_ci * returned and the struct 'res' will contain information useful to 10568c2ecf20Sopenharmony_ci * other directory manipulation functions. 10578c2ecf20Sopenharmony_ci * 10588c2ecf20Sopenharmony_ci * Caller can NOT assume anything about the contents of the 10598c2ecf20Sopenharmony_ci * buffer_heads - they are passed back only so that it can be passed 10608c2ecf20Sopenharmony_ci * into any one of the manipulation functions (add entry, delete 10618c2ecf20Sopenharmony_ci * entry, etc). As an example, bh in the extent directory case is a 10628c2ecf20Sopenharmony_ci * data block, in the inline-data case it actually points to an inode, 10638c2ecf20Sopenharmony_ci * in the indexed directory case, multiple buffers are involved. 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ciint ocfs2_find_entry(const char *name, int namelen, 10668c2ecf20Sopenharmony_ci struct inode *dir, struct ocfs2_dir_lookup_result *lookup) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci struct buffer_head *bh; 10698c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *res_dir = NULL; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) 10728c2ecf20Sopenharmony_ci return ocfs2_find_entry_dx(name, namelen, dir, lookup); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* 10758c2ecf20Sopenharmony_ci * The unindexed dir code only uses part of the lookup 10768c2ecf20Sopenharmony_ci * structure, so there's no reason to push it down further 10778c2ecf20Sopenharmony_ci * than this. 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 10808c2ecf20Sopenharmony_ci bh = ocfs2_find_entry_id(name, namelen, dir, &res_dir); 10818c2ecf20Sopenharmony_ci else 10828c2ecf20Sopenharmony_ci bh = ocfs2_find_entry_el(name, namelen, dir, &res_dir); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (bh == NULL) 10858c2ecf20Sopenharmony_ci return -ENOENT; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci lookup->dl_leaf_bh = bh; 10888c2ecf20Sopenharmony_ci lookup->dl_entry = res_dir; 10898c2ecf20Sopenharmony_ci return 0; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci/* 10938c2ecf20Sopenharmony_ci * Update inode number and type of a previously found directory entry. 10948c2ecf20Sopenharmony_ci */ 10958c2ecf20Sopenharmony_ciint ocfs2_update_entry(struct inode *dir, handle_t *handle, 10968c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *res, 10978c2ecf20Sopenharmony_ci struct inode *new_entry_inode) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci int ret; 11008c2ecf20Sopenharmony_ci ocfs2_journal_access_func access = ocfs2_journal_access_db; 11018c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de = res->dl_entry; 11028c2ecf20Sopenharmony_ci struct buffer_head *de_bh = res->dl_leaf_bh; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* 11058c2ecf20Sopenharmony_ci * The same code works fine for both inline-data and extent 11068c2ecf20Sopenharmony_ci * based directories, so no need to split this up. The only 11078c2ecf20Sopenharmony_ci * difference is the journal_access function. 11088c2ecf20Sopenharmony_ci */ 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 11118c2ecf20Sopenharmony_ci access = ocfs2_journal_access_di; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci ret = access(handle, INODE_CACHE(dir), de_bh, 11148c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 11158c2ecf20Sopenharmony_ci if (ret) { 11168c2ecf20Sopenharmony_ci mlog_errno(ret); 11178c2ecf20Sopenharmony_ci goto out; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno); 11218c2ecf20Sopenharmony_ci ocfs2_set_de_type(de, new_entry_inode->i_mode); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, de_bh); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ciout: 11268c2ecf20Sopenharmony_ci return ret; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci/* 11308c2ecf20Sopenharmony_ci * __ocfs2_delete_entry deletes a directory entry by merging it with the 11318c2ecf20Sopenharmony_ci * previous entry 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_cistatic int __ocfs2_delete_entry(handle_t *handle, struct inode *dir, 11348c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de_del, 11358c2ecf20Sopenharmony_ci struct buffer_head *bh, char *first_de, 11368c2ecf20Sopenharmony_ci unsigned int bytes) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de, *pde; 11398c2ecf20Sopenharmony_ci int i, status = -ENOENT; 11408c2ecf20Sopenharmony_ci ocfs2_journal_access_func access = ocfs2_journal_access_db; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 11438c2ecf20Sopenharmony_ci access = ocfs2_journal_access_di; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci i = 0; 11468c2ecf20Sopenharmony_ci pde = NULL; 11478c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) first_de; 11488c2ecf20Sopenharmony_ci while (i < bytes) { 11498c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(dir, de, bh, first_de, bytes, i)) { 11508c2ecf20Sopenharmony_ci status = -EIO; 11518c2ecf20Sopenharmony_ci mlog_errno(status); 11528c2ecf20Sopenharmony_ci goto bail; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci if (de == de_del) { 11558c2ecf20Sopenharmony_ci status = access(handle, INODE_CACHE(dir), bh, 11568c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 11578c2ecf20Sopenharmony_ci if (status < 0) { 11588c2ecf20Sopenharmony_ci status = -EIO; 11598c2ecf20Sopenharmony_ci mlog_errno(status); 11608c2ecf20Sopenharmony_ci goto bail; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci if (pde) 11638c2ecf20Sopenharmony_ci le16_add_cpu(&pde->rec_len, 11648c2ecf20Sopenharmony_ci le16_to_cpu(de->rec_len)); 11658c2ecf20Sopenharmony_ci de->inode = 0; 11668c2ecf20Sopenharmony_ci inode_inc_iversion(dir); 11678c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, bh); 11688c2ecf20Sopenharmony_ci goto bail; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci i += le16_to_cpu(de->rec_len); 11718c2ecf20Sopenharmony_ci pde = de; 11728c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len)); 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_cibail: 11758c2ecf20Sopenharmony_ci return status; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic unsigned int ocfs2_figure_dirent_hole(struct ocfs2_dir_entry *de) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci unsigned int hole; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (le64_to_cpu(de->inode) == 0) 11838c2ecf20Sopenharmony_ci hole = le16_to_cpu(de->rec_len); 11848c2ecf20Sopenharmony_ci else 11858c2ecf20Sopenharmony_ci hole = le16_to_cpu(de->rec_len) - 11868c2ecf20Sopenharmony_ci OCFS2_DIR_REC_LEN(de->name_len); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci return hole; 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic int ocfs2_find_max_rec_len(struct super_block *sb, 11928c2ecf20Sopenharmony_ci struct buffer_head *dirblock_bh) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci int size, this_hole, largest_hole = 0; 11958c2ecf20Sopenharmony_ci char *trailer, *de_buf, *limit, *start = dirblock_bh->b_data; 11968c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci trailer = (char *)ocfs2_trailer_from_bh(dirblock_bh, sb); 11998c2ecf20Sopenharmony_ci size = ocfs2_dir_trailer_blk_off(sb); 12008c2ecf20Sopenharmony_ci limit = start + size; 12018c2ecf20Sopenharmony_ci de_buf = start; 12028c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 12038c2ecf20Sopenharmony_ci do { 12048c2ecf20Sopenharmony_ci if (de_buf != trailer) { 12058c2ecf20Sopenharmony_ci this_hole = ocfs2_figure_dirent_hole(de); 12068c2ecf20Sopenharmony_ci if (this_hole > largest_hole) 12078c2ecf20Sopenharmony_ci largest_hole = this_hole; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci de_buf += le16_to_cpu(de->rec_len); 12118c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 12128c2ecf20Sopenharmony_ci } while (de_buf < limit); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (largest_hole >= OCFS2_DIR_MIN_REC_LEN) 12158c2ecf20Sopenharmony_ci return largest_hole; 12168c2ecf20Sopenharmony_ci return 0; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic void ocfs2_dx_list_remove_entry(struct ocfs2_dx_entry_list *entry_list, 12208c2ecf20Sopenharmony_ci int index) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci int num_used = le16_to_cpu(entry_list->de_num_used); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (num_used == 1 || index == (num_used - 1)) 12258c2ecf20Sopenharmony_ci goto clear; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci memmove(&entry_list->de_entries[index], 12288c2ecf20Sopenharmony_ci &entry_list->de_entries[index + 1], 12298c2ecf20Sopenharmony_ci (num_used - index - 1)*sizeof(struct ocfs2_dx_entry)); 12308c2ecf20Sopenharmony_ciclear: 12318c2ecf20Sopenharmony_ci num_used--; 12328c2ecf20Sopenharmony_ci memset(&entry_list->de_entries[num_used], 0, 12338c2ecf20Sopenharmony_ci sizeof(struct ocfs2_dx_entry)); 12348c2ecf20Sopenharmony_ci entry_list->de_num_used = cpu_to_le16(num_used); 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, 12388c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci int ret, index, max_rec_len, add_to_free_list = 0; 12418c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh; 12428c2ecf20Sopenharmony_ci struct buffer_head *leaf_bh = lookup->dl_leaf_bh; 12438c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf; 12448c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *dx_entry = lookup->dl_dx_entry; 12458c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer; 12468c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 12478c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *entry_list; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* 12508c2ecf20Sopenharmony_ci * This function gets a bit messy because we might have to 12518c2ecf20Sopenharmony_ci * modify the root block, regardless of whether the indexed 12528c2ecf20Sopenharmony_ci * entries are stored inline. 12538c2ecf20Sopenharmony_ci */ 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* 12568c2ecf20Sopenharmony_ci * *Only* set 'entry_list' here, based on where we're looking 12578c2ecf20Sopenharmony_ci * for the indexed entries. Later, we might still want to 12588c2ecf20Sopenharmony_ci * journal both blocks, based on free list state. 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 12618c2ecf20Sopenharmony_ci if (ocfs2_dx_root_inline(dx_root)) { 12628c2ecf20Sopenharmony_ci entry_list = &dx_root->dr_entries; 12638c2ecf20Sopenharmony_ci } else { 12648c2ecf20Sopenharmony_ci dx_leaf = (struct ocfs2_dx_leaf *) lookup->dl_dx_leaf_bh->b_data; 12658c2ecf20Sopenharmony_ci entry_list = &dx_leaf->dl_list; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Neither of these are a disk corruption - that should have 12698c2ecf20Sopenharmony_ci * been caught by lookup, before we got here. */ 12708c2ecf20Sopenharmony_ci BUG_ON(le16_to_cpu(entry_list->de_count) <= 0); 12718c2ecf20Sopenharmony_ci BUG_ON(le16_to_cpu(entry_list->de_num_used) <= 0); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci index = (char *)dx_entry - (char *)entry_list->de_entries; 12748c2ecf20Sopenharmony_ci index /= sizeof(*dx_entry); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (index >= le16_to_cpu(entry_list->de_num_used)) { 12778c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Dir %llu: Bad dx_entry ptr idx %d, (%p, %p)\n", 12788c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, index, 12798c2ecf20Sopenharmony_ci entry_list, dx_entry); 12808c2ecf20Sopenharmony_ci return -EIO; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* 12848c2ecf20Sopenharmony_ci * We know that removal of this dirent will leave enough room 12858c2ecf20Sopenharmony_ci * for a new one, so add this block to the free list if it 12868c2ecf20Sopenharmony_ci * isn't already there. 12878c2ecf20Sopenharmony_ci */ 12888c2ecf20Sopenharmony_ci trailer = ocfs2_trailer_from_bh(leaf_bh, dir->i_sb); 12898c2ecf20Sopenharmony_ci if (trailer->db_free_rec_len == 0) 12908c2ecf20Sopenharmony_ci add_to_free_list = 1; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* 12938c2ecf20Sopenharmony_ci * Add the block holding our index into the journal before 12948c2ecf20Sopenharmony_ci * removing the unindexed entry. If we get an error return 12958c2ecf20Sopenharmony_ci * from __ocfs2_delete_entry(), then it hasn't removed the 12968c2ecf20Sopenharmony_ci * entry yet. Likewise, successful return means we *must* 12978c2ecf20Sopenharmony_ci * remove the indexed entry. 12988c2ecf20Sopenharmony_ci * 12998c2ecf20Sopenharmony_ci * We're also careful to journal the root tree block here as 13008c2ecf20Sopenharmony_ci * the entry count needs to be updated. Also, we might be 13018c2ecf20Sopenharmony_ci * adding to the start of the free list. 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh, 13048c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 13058c2ecf20Sopenharmony_ci if (ret) { 13068c2ecf20Sopenharmony_ci mlog_errno(ret); 13078c2ecf20Sopenharmony_ci goto out; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (!ocfs2_dx_root_inline(dx_root)) { 13118c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), 13128c2ecf20Sopenharmony_ci lookup->dl_dx_leaf_bh, 13138c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 13148c2ecf20Sopenharmony_ci if (ret) { 13158c2ecf20Sopenharmony_ci mlog_errno(ret); 13168c2ecf20Sopenharmony_ci goto out; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci trace_ocfs2_delete_entry_dx((unsigned long long)OCFS2_I(dir)->ip_blkno, 13218c2ecf20Sopenharmony_ci index); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci ret = __ocfs2_delete_entry(handle, dir, lookup->dl_entry, 13248c2ecf20Sopenharmony_ci leaf_bh, leaf_bh->b_data, leaf_bh->b_size); 13258c2ecf20Sopenharmony_ci if (ret) { 13268c2ecf20Sopenharmony_ci mlog_errno(ret); 13278c2ecf20Sopenharmony_ci goto out; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci max_rec_len = ocfs2_find_max_rec_len(dir->i_sb, leaf_bh); 13318c2ecf20Sopenharmony_ci trailer->db_free_rec_len = cpu_to_le16(max_rec_len); 13328c2ecf20Sopenharmony_ci if (add_to_free_list) { 13338c2ecf20Sopenharmony_ci trailer->db_free_next = dx_root->dr_free_blk; 13348c2ecf20Sopenharmony_ci dx_root->dr_free_blk = cpu_to_le64(leaf_bh->b_blocknr); 13358c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_root_bh); 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* leaf_bh was journal_accessed for us in __ocfs2_delete_entry */ 13398c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, leaf_bh); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci le32_add_cpu(&dx_root->dr_num_entries, -1); 13428c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_root_bh); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci ocfs2_dx_list_remove_entry(entry_list, index); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (!ocfs2_dx_root_inline(dx_root)) 13478c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ciout: 13508c2ecf20Sopenharmony_ci return ret; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic inline int ocfs2_delete_entry_id(handle_t *handle, 13548c2ecf20Sopenharmony_ci struct inode *dir, 13558c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de_del, 13568c2ecf20Sopenharmony_ci struct buffer_head *bh) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci int ret; 13598c2ecf20Sopenharmony_ci struct buffer_head *di_bh = NULL; 13608c2ecf20Sopenharmony_ci struct ocfs2_dinode *di; 13618c2ecf20Sopenharmony_ci struct ocfs2_inline_data *data; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci ret = ocfs2_read_inode_block(dir, &di_bh); 13648c2ecf20Sopenharmony_ci if (ret) { 13658c2ecf20Sopenharmony_ci mlog_errno(ret); 13668c2ecf20Sopenharmony_ci goto out; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci di = (struct ocfs2_dinode *)di_bh->b_data; 13708c2ecf20Sopenharmony_ci data = &di->id2.i_data; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci ret = __ocfs2_delete_entry(handle, dir, de_del, bh, data->id_data, 13738c2ecf20Sopenharmony_ci i_size_read(dir)); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci brelse(di_bh); 13768c2ecf20Sopenharmony_ciout: 13778c2ecf20Sopenharmony_ci return ret; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic inline int ocfs2_delete_entry_el(handle_t *handle, 13818c2ecf20Sopenharmony_ci struct inode *dir, 13828c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de_del, 13838c2ecf20Sopenharmony_ci struct buffer_head *bh) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci return __ocfs2_delete_entry(handle, dir, de_del, bh, bh->b_data, 13868c2ecf20Sopenharmony_ci bh->b_size); 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci/* 13908c2ecf20Sopenharmony_ci * Delete a directory entry. Hide the details of directory 13918c2ecf20Sopenharmony_ci * implementation from the caller. 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ciint ocfs2_delete_entry(handle_t *handle, 13948c2ecf20Sopenharmony_ci struct inode *dir, 13958c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *res) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) 13988c2ecf20Sopenharmony_ci return ocfs2_delete_entry_dx(handle, dir, res); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 14018c2ecf20Sopenharmony_ci return ocfs2_delete_entry_id(handle, dir, res->dl_entry, 14028c2ecf20Sopenharmony_ci res->dl_leaf_bh); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return ocfs2_delete_entry_el(handle, dir, res->dl_entry, 14058c2ecf20Sopenharmony_ci res->dl_leaf_bh); 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci/* 14098c2ecf20Sopenharmony_ci * Check whether 'de' has enough room to hold an entry of 14108c2ecf20Sopenharmony_ci * 'new_rec_len' bytes. 14118c2ecf20Sopenharmony_ci */ 14128c2ecf20Sopenharmony_cistatic inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de, 14138c2ecf20Sopenharmony_ci unsigned int new_rec_len) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci unsigned int de_really_used; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* Check whether this is an empty record with enough space */ 14188c2ecf20Sopenharmony_ci if (le64_to_cpu(de->inode) == 0 && 14198c2ecf20Sopenharmony_ci le16_to_cpu(de->rec_len) >= new_rec_len) 14208c2ecf20Sopenharmony_ci return 1; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci /* 14238c2ecf20Sopenharmony_ci * Record might have free space at the end which we can 14248c2ecf20Sopenharmony_ci * use. 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_ci de_really_used = OCFS2_DIR_REC_LEN(de->name_len); 14278c2ecf20Sopenharmony_ci if (le16_to_cpu(de->rec_len) >= (de_really_used + new_rec_len)) 14288c2ecf20Sopenharmony_ci return 1; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return 0; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistatic void ocfs2_dx_dir_leaf_insert_tail(struct ocfs2_dx_leaf *dx_leaf, 14348c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *dx_new_entry) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci int i; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci i = le16_to_cpu(dx_leaf->dl_list.de_num_used); 14398c2ecf20Sopenharmony_ci dx_leaf->dl_list.de_entries[i] = *dx_new_entry; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci le16_add_cpu(&dx_leaf->dl_list.de_num_used, 1); 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_cistatic void ocfs2_dx_entry_list_insert(struct ocfs2_dx_entry_list *entry_list, 14458c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo, 14468c2ecf20Sopenharmony_ci u64 dirent_blk) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci int i; 14498c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *dx_entry; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci i = le16_to_cpu(entry_list->de_num_used); 14528c2ecf20Sopenharmony_ci dx_entry = &entry_list->de_entries[i]; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci memset(dx_entry, 0, sizeof(*dx_entry)); 14558c2ecf20Sopenharmony_ci dx_entry->dx_major_hash = cpu_to_le32(hinfo->major_hash); 14568c2ecf20Sopenharmony_ci dx_entry->dx_minor_hash = cpu_to_le32(hinfo->minor_hash); 14578c2ecf20Sopenharmony_ci dx_entry->dx_dirent_blk = cpu_to_le64(dirent_blk); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci le16_add_cpu(&entry_list->de_num_used, 1); 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cistatic int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle, 14638c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo, 14648c2ecf20Sopenharmony_ci u64 dirent_blk, 14658c2ecf20Sopenharmony_ci struct buffer_head *dx_leaf_bh) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci int ret; 14688c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), dx_leaf_bh, 14718c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 14728c2ecf20Sopenharmony_ci if (ret) { 14738c2ecf20Sopenharmony_ci mlog_errno(ret); 14748c2ecf20Sopenharmony_ci goto out; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data; 14788c2ecf20Sopenharmony_ci ocfs2_dx_entry_list_insert(&dx_leaf->dl_list, hinfo, dirent_blk); 14798c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_leaf_bh); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ciout: 14828c2ecf20Sopenharmony_ci return ret; 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_cistatic void ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, 14868c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo, 14878c2ecf20Sopenharmony_ci u64 dirent_blk, 14888c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk); 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle, 14948c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci int ret = 0; 14978c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 14988c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh, 15018c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 15028c2ecf20Sopenharmony_ci if (ret) { 15038c2ecf20Sopenharmony_ci mlog_errno(ret); 15048c2ecf20Sopenharmony_ci goto out; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data; 15088c2ecf20Sopenharmony_ci if (ocfs2_dx_root_inline(dx_root)) { 15098c2ecf20Sopenharmony_ci ocfs2_dx_inline_root_insert(dir, handle, 15108c2ecf20Sopenharmony_ci &lookup->dl_hinfo, 15118c2ecf20Sopenharmony_ci lookup->dl_leaf_bh->b_blocknr, 15128c2ecf20Sopenharmony_ci dx_root); 15138c2ecf20Sopenharmony_ci } else { 15148c2ecf20Sopenharmony_ci ret = __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo, 15158c2ecf20Sopenharmony_ci lookup->dl_leaf_bh->b_blocknr, 15168c2ecf20Sopenharmony_ci lookup->dl_dx_leaf_bh); 15178c2ecf20Sopenharmony_ci if (ret) 15188c2ecf20Sopenharmony_ci goto out; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci le32_add_cpu(&dx_root->dr_num_entries, 1); 15228c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_root_bh); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ciout: 15258c2ecf20Sopenharmony_ci return ret; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic void ocfs2_remove_block_from_free_list(struct inode *dir, 15298c2ecf20Sopenharmony_ci handle_t *handle, 15308c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer, *prev; 15338c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 15348c2ecf20Sopenharmony_ci struct buffer_head *bh; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci trailer = ocfs2_trailer_from_bh(lookup->dl_leaf_bh, dir->i_sb); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (ocfs2_free_list_at_root(lookup)) { 15398c2ecf20Sopenharmony_ci bh = lookup->dl_dx_root_bh; 15408c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)bh->b_data; 15418c2ecf20Sopenharmony_ci dx_root->dr_free_blk = trailer->db_free_next; 15428c2ecf20Sopenharmony_ci } else { 15438c2ecf20Sopenharmony_ci bh = lookup->dl_prev_leaf_bh; 15448c2ecf20Sopenharmony_ci prev = ocfs2_trailer_from_bh(bh, dir->i_sb); 15458c2ecf20Sopenharmony_ci prev->db_free_next = trailer->db_free_next; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci trailer->db_free_rec_len = cpu_to_le16(0); 15498c2ecf20Sopenharmony_ci trailer->db_free_next = cpu_to_le64(0); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, bh); 15528c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, lookup->dl_leaf_bh); 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci/* 15568c2ecf20Sopenharmony_ci * This expects that a journal write has been reserved on 15578c2ecf20Sopenharmony_ci * lookup->dl_prev_leaf_bh or lookup->dl_dx_root_bh 15588c2ecf20Sopenharmony_ci */ 15598c2ecf20Sopenharmony_cistatic void ocfs2_recalc_free_list(struct inode *dir, handle_t *handle, 15608c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci int max_rec_len; 15638c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* Walk dl_leaf_bh to figure out what the new free rec_len is. */ 15668c2ecf20Sopenharmony_ci max_rec_len = ocfs2_find_max_rec_len(dir->i_sb, lookup->dl_leaf_bh); 15678c2ecf20Sopenharmony_ci if (max_rec_len) { 15688c2ecf20Sopenharmony_ci /* 15698c2ecf20Sopenharmony_ci * There's still room in this block, so no need to remove it 15708c2ecf20Sopenharmony_ci * from the free list. In this case, we just want to update 15718c2ecf20Sopenharmony_ci * the rec len accounting. 15728c2ecf20Sopenharmony_ci */ 15738c2ecf20Sopenharmony_ci trailer = ocfs2_trailer_from_bh(lookup->dl_leaf_bh, dir->i_sb); 15748c2ecf20Sopenharmony_ci trailer->db_free_rec_len = cpu_to_le16(max_rec_len); 15758c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, lookup->dl_leaf_bh); 15768c2ecf20Sopenharmony_ci } else { 15778c2ecf20Sopenharmony_ci ocfs2_remove_block_from_free_list(dir, handle, lookup); 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci/* we don't always have a dentry for what we want to add, so people 15828c2ecf20Sopenharmony_ci * like orphan dir can call this instead. 15838c2ecf20Sopenharmony_ci * 15848c2ecf20Sopenharmony_ci * The lookup context must have been filled from 15858c2ecf20Sopenharmony_ci * ocfs2_prepare_dir_for_insert. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ciint __ocfs2_add_entry(handle_t *handle, 15888c2ecf20Sopenharmony_ci struct inode *dir, 15898c2ecf20Sopenharmony_ci const char *name, int namelen, 15908c2ecf20Sopenharmony_ci struct inode *inode, u64 blkno, 15918c2ecf20Sopenharmony_ci struct buffer_head *parent_fe_bh, 15928c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 15938c2ecf20Sopenharmony_ci{ 15948c2ecf20Sopenharmony_ci unsigned long offset; 15958c2ecf20Sopenharmony_ci unsigned short rec_len; 15968c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de, *de1; 15978c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data; 15988c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 15998c2ecf20Sopenharmony_ci int retval; 16008c2ecf20Sopenharmony_ci unsigned int size = sb->s_blocksize; 16018c2ecf20Sopenharmony_ci struct buffer_head *insert_bh = lookup->dl_leaf_bh; 16028c2ecf20Sopenharmony_ci char *data_start = insert_bh->b_data; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (!namelen) 16058c2ecf20Sopenharmony_ci return -EINVAL; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) { 16088c2ecf20Sopenharmony_ci struct buffer_head *bh; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci /* 16118c2ecf20Sopenharmony_ci * An indexed dir may require that we update the free space 16128c2ecf20Sopenharmony_ci * list. Reserve a write to the previous node in the list so 16138c2ecf20Sopenharmony_ci * that we don't fail later. 16148c2ecf20Sopenharmony_ci * 16158c2ecf20Sopenharmony_ci * XXX: This can be either a dx_root_block, or an unindexed 16168c2ecf20Sopenharmony_ci * directory tree leaf block. 16178c2ecf20Sopenharmony_ci */ 16188c2ecf20Sopenharmony_ci if (ocfs2_free_list_at_root(lookup)) { 16198c2ecf20Sopenharmony_ci bh = lookup->dl_dx_root_bh; 16208c2ecf20Sopenharmony_ci retval = ocfs2_journal_access_dr(handle, 16218c2ecf20Sopenharmony_ci INODE_CACHE(dir), bh, 16228c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 16238c2ecf20Sopenharmony_ci } else { 16248c2ecf20Sopenharmony_ci bh = lookup->dl_prev_leaf_bh; 16258c2ecf20Sopenharmony_ci retval = ocfs2_journal_access_db(handle, 16268c2ecf20Sopenharmony_ci INODE_CACHE(dir), bh, 16278c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci if (retval) { 16308c2ecf20Sopenharmony_ci mlog_errno(retval); 16318c2ecf20Sopenharmony_ci return retval; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci } else if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { 16348c2ecf20Sopenharmony_ci data_start = di->id2.i_data.id_data; 16358c2ecf20Sopenharmony_ci size = i_size_read(dir); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci BUG_ON(insert_bh != parent_fe_bh); 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci rec_len = OCFS2_DIR_REC_LEN(namelen); 16418c2ecf20Sopenharmony_ci offset = 0; 16428c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) data_start; 16438c2ecf20Sopenharmony_ci while (1) { 16448c2ecf20Sopenharmony_ci BUG_ON((char *)de >= (size + data_start)); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci /* These checks should've already been passed by the 16478c2ecf20Sopenharmony_ci * prepare function, but I guess we can leave them 16488c2ecf20Sopenharmony_ci * here anyway. */ 16498c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(dir, de, insert_bh, data_start, 16508c2ecf20Sopenharmony_ci size, offset)) { 16518c2ecf20Sopenharmony_ci retval = -ENOENT; 16528c2ecf20Sopenharmony_ci goto bail; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci if (ocfs2_match(namelen, name, de)) { 16558c2ecf20Sopenharmony_ci retval = -EEXIST; 16568c2ecf20Sopenharmony_ci goto bail; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* We're guaranteed that we should have space, so we 16608c2ecf20Sopenharmony_ci * can't possibly have hit the trailer...right? */ 16618c2ecf20Sopenharmony_ci mlog_bug_on_msg(ocfs2_skip_dir_trailer(dir, de, offset, size), 16628c2ecf20Sopenharmony_ci "Hit dir trailer trying to insert %.*s " 16638c2ecf20Sopenharmony_ci "(namelen %d) into directory %llu. " 16648c2ecf20Sopenharmony_ci "offset is %lu, trailer offset is %d\n", 16658c2ecf20Sopenharmony_ci namelen, name, namelen, 16668c2ecf20Sopenharmony_ci (unsigned long long)parent_fe_bh->b_blocknr, 16678c2ecf20Sopenharmony_ci offset, ocfs2_dir_trailer_blk_off(dir->i_sb)); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci if (ocfs2_dirent_would_fit(de, rec_len)) { 16708c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = current_time(dir); 16718c2ecf20Sopenharmony_ci retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); 16728c2ecf20Sopenharmony_ci if (retval < 0) { 16738c2ecf20Sopenharmony_ci mlog_errno(retval); 16748c2ecf20Sopenharmony_ci goto bail; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (insert_bh == parent_fe_bh) 16788c2ecf20Sopenharmony_ci retval = ocfs2_journal_access_di(handle, 16798c2ecf20Sopenharmony_ci INODE_CACHE(dir), 16808c2ecf20Sopenharmony_ci insert_bh, 16818c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 16828c2ecf20Sopenharmony_ci else { 16838c2ecf20Sopenharmony_ci retval = ocfs2_journal_access_db(handle, 16848c2ecf20Sopenharmony_ci INODE_CACHE(dir), 16858c2ecf20Sopenharmony_ci insert_bh, 16868c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (!retval && ocfs2_dir_indexed(dir)) 16898c2ecf20Sopenharmony_ci retval = ocfs2_dx_dir_insert(dir, 16908c2ecf20Sopenharmony_ci handle, 16918c2ecf20Sopenharmony_ci lookup); 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (retval) { 16958c2ecf20Sopenharmony_ci mlog_errno(retval); 16968c2ecf20Sopenharmony_ci goto bail; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* By now the buffer is marked for journaling */ 17008c2ecf20Sopenharmony_ci offset += le16_to_cpu(de->rec_len); 17018c2ecf20Sopenharmony_ci if (le64_to_cpu(de->inode)) { 17028c2ecf20Sopenharmony_ci de1 = (struct ocfs2_dir_entry *)((char *) de + 17038c2ecf20Sopenharmony_ci OCFS2_DIR_REC_LEN(de->name_len)); 17048c2ecf20Sopenharmony_ci de1->rec_len = 17058c2ecf20Sopenharmony_ci cpu_to_le16(le16_to_cpu(de->rec_len) - 17068c2ecf20Sopenharmony_ci OCFS2_DIR_REC_LEN(de->name_len)); 17078c2ecf20Sopenharmony_ci de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); 17088c2ecf20Sopenharmony_ci de = de1; 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci de->file_type = FT_UNKNOWN; 17118c2ecf20Sopenharmony_ci if (blkno) { 17128c2ecf20Sopenharmony_ci de->inode = cpu_to_le64(blkno); 17138c2ecf20Sopenharmony_ci ocfs2_set_de_type(de, inode->i_mode); 17148c2ecf20Sopenharmony_ci } else 17158c2ecf20Sopenharmony_ci de->inode = 0; 17168c2ecf20Sopenharmony_ci de->name_len = namelen; 17178c2ecf20Sopenharmony_ci memcpy(de->name, name, namelen); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) 17208c2ecf20Sopenharmony_ci ocfs2_recalc_free_list(dir, handle, lookup); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci inode_inc_iversion(dir); 17238c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, insert_bh); 17248c2ecf20Sopenharmony_ci retval = 0; 17258c2ecf20Sopenharmony_ci goto bail; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci offset += le16_to_cpu(de->rec_len); 17298c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* when you think about it, the assert above should prevent us 17338c2ecf20Sopenharmony_ci * from ever getting here. */ 17348c2ecf20Sopenharmony_ci retval = -ENOSPC; 17358c2ecf20Sopenharmony_cibail: 17368c2ecf20Sopenharmony_ci if (retval) 17378c2ecf20Sopenharmony_ci mlog_errno(retval); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci return retval; 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_cistatic int ocfs2_dir_foreach_blk_id(struct inode *inode, 17438c2ecf20Sopenharmony_ci u64 *f_version, 17448c2ecf20Sopenharmony_ci struct dir_context *ctx) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci int ret, i; 17478c2ecf20Sopenharmony_ci unsigned long offset = ctx->pos; 17488c2ecf20Sopenharmony_ci struct buffer_head *di_bh = NULL; 17498c2ecf20Sopenharmony_ci struct ocfs2_dinode *di; 17508c2ecf20Sopenharmony_ci struct ocfs2_inline_data *data; 17518c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci ret = ocfs2_read_inode_block(inode, &di_bh); 17548c2ecf20Sopenharmony_ci if (ret) { 17558c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", 17568c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(inode)->ip_blkno); 17578c2ecf20Sopenharmony_ci goto out; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci di = (struct ocfs2_dinode *)di_bh->b_data; 17618c2ecf20Sopenharmony_ci data = &di->id2.i_data; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci while (ctx->pos < i_size_read(inode)) { 17648c2ecf20Sopenharmony_ci /* If the dir block has changed since the last call to 17658c2ecf20Sopenharmony_ci * readdir(2), then we might be pointing to an invalid 17668c2ecf20Sopenharmony_ci * dirent right now. Scan from the start of the block 17678c2ecf20Sopenharmony_ci * to make sure. */ 17688c2ecf20Sopenharmony_ci if (!inode_eq_iversion(inode, *f_version)) { 17698c2ecf20Sopenharmony_ci for (i = 0; i < i_size_read(inode) && i < offset; ) { 17708c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) 17718c2ecf20Sopenharmony_ci (data->id_data + i); 17728c2ecf20Sopenharmony_ci /* It's too expensive to do a full 17738c2ecf20Sopenharmony_ci * dirent test each time round this 17748c2ecf20Sopenharmony_ci * loop, but we do have to test at 17758c2ecf20Sopenharmony_ci * least that it is non-zero. A 17768c2ecf20Sopenharmony_ci * failure will be detected in the 17778c2ecf20Sopenharmony_ci * dirent test below. */ 17788c2ecf20Sopenharmony_ci if (le16_to_cpu(de->rec_len) < 17798c2ecf20Sopenharmony_ci OCFS2_DIR_REC_LEN(1)) 17808c2ecf20Sopenharmony_ci break; 17818c2ecf20Sopenharmony_ci i += le16_to_cpu(de->rec_len); 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci ctx->pos = offset = i; 17848c2ecf20Sopenharmony_ci *f_version = inode_query_iversion(inode); 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) (data->id_data + ctx->pos); 17888c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(inode, de, di_bh, (char *)data->id_data, 17898c2ecf20Sopenharmony_ci i_size_read(inode), ctx->pos)) { 17908c2ecf20Sopenharmony_ci /* On error, skip the f_pos to the end. */ 17918c2ecf20Sopenharmony_ci ctx->pos = i_size_read(inode); 17928c2ecf20Sopenharmony_ci break; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci offset += le16_to_cpu(de->rec_len); 17958c2ecf20Sopenharmony_ci if (le64_to_cpu(de->inode)) { 17968c2ecf20Sopenharmony_ci if (!dir_emit(ctx, de->name, de->name_len, 17978c2ecf20Sopenharmony_ci le64_to_cpu(de->inode), 17988c2ecf20Sopenharmony_ci fs_ftype_to_dtype(de->file_type))) 17998c2ecf20Sopenharmony_ci goto out; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci ctx->pos += le16_to_cpu(de->rec_len); 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ciout: 18048c2ecf20Sopenharmony_ci brelse(di_bh); 18058c2ecf20Sopenharmony_ci return 0; 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci/* 18098c2ecf20Sopenharmony_ci * NOTE: This function can be called against unindexed directories, 18108c2ecf20Sopenharmony_ci * and indexed ones. 18118c2ecf20Sopenharmony_ci */ 18128c2ecf20Sopenharmony_cistatic int ocfs2_dir_foreach_blk_el(struct inode *inode, 18138c2ecf20Sopenharmony_ci u64 *f_version, 18148c2ecf20Sopenharmony_ci struct dir_context *ctx, 18158c2ecf20Sopenharmony_ci bool persist) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci unsigned long offset, blk, last_ra_blk = 0; 18188c2ecf20Sopenharmony_ci int i; 18198c2ecf20Sopenharmony_ci struct buffer_head * bh, * tmp; 18208c2ecf20Sopenharmony_ci struct ocfs2_dir_entry * de; 18218c2ecf20Sopenharmony_ci struct super_block * sb = inode->i_sb; 18228c2ecf20Sopenharmony_ci unsigned int ra_sectors = 16; 18238c2ecf20Sopenharmony_ci int stored = 0; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci bh = NULL; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci offset = ctx->pos & (sb->s_blocksize - 1); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci while (ctx->pos < i_size_read(inode)) { 18308c2ecf20Sopenharmony_ci blk = ctx->pos >> sb->s_blocksize_bits; 18318c2ecf20Sopenharmony_ci if (ocfs2_read_dir_block(inode, blk, &bh, 0)) { 18328c2ecf20Sopenharmony_ci /* Skip the corrupt dirblock and keep trying */ 18338c2ecf20Sopenharmony_ci ctx->pos += sb->s_blocksize - offset; 18348c2ecf20Sopenharmony_ci continue; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci /* The idea here is to begin with 8k read-ahead and to stay 18388c2ecf20Sopenharmony_ci * 4k ahead of our current position. 18398c2ecf20Sopenharmony_ci * 18408c2ecf20Sopenharmony_ci * TODO: Use the pagecache for this. We just need to 18418c2ecf20Sopenharmony_ci * make sure it's cluster-safe... */ 18428c2ecf20Sopenharmony_ci if (!last_ra_blk 18438c2ecf20Sopenharmony_ci || (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) { 18448c2ecf20Sopenharmony_ci for (i = ra_sectors >> (sb->s_blocksize_bits - 9); 18458c2ecf20Sopenharmony_ci i > 0; i--) { 18468c2ecf20Sopenharmony_ci tmp = NULL; 18478c2ecf20Sopenharmony_ci if (!ocfs2_read_dir_block(inode, ++blk, &tmp, 18488c2ecf20Sopenharmony_ci OCFS2_BH_READAHEAD)) 18498c2ecf20Sopenharmony_ci brelse(tmp); 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci last_ra_blk = blk; 18528c2ecf20Sopenharmony_ci ra_sectors = 8; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* If the dir block has changed since the last call to 18568c2ecf20Sopenharmony_ci * readdir(2), then we might be pointing to an invalid 18578c2ecf20Sopenharmony_ci * dirent right now. Scan from the start of the block 18588c2ecf20Sopenharmony_ci * to make sure. */ 18598c2ecf20Sopenharmony_ci if (!inode_eq_iversion(inode, *f_version)) { 18608c2ecf20Sopenharmony_ci for (i = 0; i < sb->s_blocksize && i < offset; ) { 18618c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) (bh->b_data + i); 18628c2ecf20Sopenharmony_ci /* It's too expensive to do a full 18638c2ecf20Sopenharmony_ci * dirent test each time round this 18648c2ecf20Sopenharmony_ci * loop, but we do have to test at 18658c2ecf20Sopenharmony_ci * least that it is non-zero. A 18668c2ecf20Sopenharmony_ci * failure will be detected in the 18678c2ecf20Sopenharmony_ci * dirent test below. */ 18688c2ecf20Sopenharmony_ci if (le16_to_cpu(de->rec_len) < 18698c2ecf20Sopenharmony_ci OCFS2_DIR_REC_LEN(1)) 18708c2ecf20Sopenharmony_ci break; 18718c2ecf20Sopenharmony_ci i += le16_to_cpu(de->rec_len); 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci offset = i; 18748c2ecf20Sopenharmony_ci ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1)) 18758c2ecf20Sopenharmony_ci | offset; 18768c2ecf20Sopenharmony_ci *f_version = inode_query_iversion(inode); 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci while (ctx->pos < i_size_read(inode) 18808c2ecf20Sopenharmony_ci && offset < sb->s_blocksize) { 18818c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) (bh->b_data + offset); 18828c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(inode, de, bh, bh->b_data, 18838c2ecf20Sopenharmony_ci sb->s_blocksize, offset)) { 18848c2ecf20Sopenharmony_ci /* On error, skip the f_pos to the 18858c2ecf20Sopenharmony_ci next block. */ 18868c2ecf20Sopenharmony_ci ctx->pos = (ctx->pos | (sb->s_blocksize - 1)) + 1; 18878c2ecf20Sopenharmony_ci break; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci if (le64_to_cpu(de->inode)) { 18908c2ecf20Sopenharmony_ci if (!dir_emit(ctx, de->name, 18918c2ecf20Sopenharmony_ci de->name_len, 18928c2ecf20Sopenharmony_ci le64_to_cpu(de->inode), 18938c2ecf20Sopenharmony_ci fs_ftype_to_dtype(de->file_type))) { 18948c2ecf20Sopenharmony_ci brelse(bh); 18958c2ecf20Sopenharmony_ci return 0; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci stored++; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci offset += le16_to_cpu(de->rec_len); 19008c2ecf20Sopenharmony_ci ctx->pos += le16_to_cpu(de->rec_len); 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci offset = 0; 19038c2ecf20Sopenharmony_ci brelse(bh); 19048c2ecf20Sopenharmony_ci bh = NULL; 19058c2ecf20Sopenharmony_ci if (!persist && stored) 19068c2ecf20Sopenharmony_ci break; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci return 0; 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_cistatic int ocfs2_dir_foreach_blk(struct inode *inode, u64 *f_version, 19128c2ecf20Sopenharmony_ci struct dir_context *ctx, 19138c2ecf20Sopenharmony_ci bool persist) 19148c2ecf20Sopenharmony_ci{ 19158c2ecf20Sopenharmony_ci if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 19168c2ecf20Sopenharmony_ci return ocfs2_dir_foreach_blk_id(inode, f_version, ctx); 19178c2ecf20Sopenharmony_ci return ocfs2_dir_foreach_blk_el(inode, f_version, ctx, persist); 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci/* 19218c2ecf20Sopenharmony_ci * This is intended to be called from inside other kernel functions, 19228c2ecf20Sopenharmony_ci * so we fake some arguments. 19238c2ecf20Sopenharmony_ci */ 19248c2ecf20Sopenharmony_ciint ocfs2_dir_foreach(struct inode *inode, struct dir_context *ctx) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci u64 version = inode_query_iversion(inode); 19278c2ecf20Sopenharmony_ci ocfs2_dir_foreach_blk(inode, &version, ctx, true); 19288c2ecf20Sopenharmony_ci return 0; 19298c2ecf20Sopenharmony_ci} 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci/* 19328c2ecf20Sopenharmony_ci * ocfs2_readdir() 19338c2ecf20Sopenharmony_ci * 19348c2ecf20Sopenharmony_ci */ 19358c2ecf20Sopenharmony_ciint ocfs2_readdir(struct file *file, struct dir_context *ctx) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci int error = 0; 19388c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 19398c2ecf20Sopenharmony_ci int lock_level = 0; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci trace_ocfs2_readdir((unsigned long long)OCFS2_I(inode)->ip_blkno); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci error = ocfs2_inode_lock_atime(inode, file->f_path.mnt, &lock_level, 1); 19448c2ecf20Sopenharmony_ci if (lock_level && error >= 0) { 19458c2ecf20Sopenharmony_ci /* We release EX lock which used to update atime 19468c2ecf20Sopenharmony_ci * and get PR lock again to reduce contention 19478c2ecf20Sopenharmony_ci * on commonly accessed directories. */ 19488c2ecf20Sopenharmony_ci ocfs2_inode_unlock(inode, 1); 19498c2ecf20Sopenharmony_ci lock_level = 0; 19508c2ecf20Sopenharmony_ci error = ocfs2_inode_lock(inode, NULL, 0); 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci if (error < 0) { 19538c2ecf20Sopenharmony_ci if (error != -ENOENT) 19548c2ecf20Sopenharmony_ci mlog_errno(error); 19558c2ecf20Sopenharmony_ci /* we haven't got any yet, so propagate the error. */ 19568c2ecf20Sopenharmony_ci goto bail_nolock; 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci error = ocfs2_dir_foreach_blk(inode, &file->f_version, ctx, false); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci ocfs2_inode_unlock(inode, lock_level); 19628c2ecf20Sopenharmony_ci if (error) 19638c2ecf20Sopenharmony_ci mlog_errno(error); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_cibail_nolock: 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci return error; 19688c2ecf20Sopenharmony_ci} 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci/* 19718c2ecf20Sopenharmony_ci * NOTE: this should always be called with parent dir i_mutex taken. 19728c2ecf20Sopenharmony_ci */ 19738c2ecf20Sopenharmony_ciint ocfs2_find_files_on_disk(const char *name, 19748c2ecf20Sopenharmony_ci int namelen, 19758c2ecf20Sopenharmony_ci u64 *blkno, 19768c2ecf20Sopenharmony_ci struct inode *inode, 19778c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci int status = -ENOENT; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci trace_ocfs2_find_files_on_disk(namelen, name, blkno, 19828c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(inode)->ip_blkno); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci status = ocfs2_find_entry(name, namelen, inode, lookup); 19858c2ecf20Sopenharmony_ci if (status) 19868c2ecf20Sopenharmony_ci goto leave; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci *blkno = le64_to_cpu(lookup->dl_entry->inode); 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci status = 0; 19918c2ecf20Sopenharmony_cileave: 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci return status; 19948c2ecf20Sopenharmony_ci} 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci/* 19978c2ecf20Sopenharmony_ci * Convenience function for callers which just want the block number 19988c2ecf20Sopenharmony_ci * mapped to a name and don't require the full dirent info, etc. 19998c2ecf20Sopenharmony_ci */ 20008c2ecf20Sopenharmony_ciint ocfs2_lookup_ino_from_name(struct inode *dir, const char *name, 20018c2ecf20Sopenharmony_ci int namelen, u64 *blkno) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci int ret; 20048c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result lookup = { NULL, }; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &lookup); 20078c2ecf20Sopenharmony_ci ocfs2_free_dir_lookup_result(&lookup); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci return ret; 20108c2ecf20Sopenharmony_ci} 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci/* Check for a name within a directory. 20138c2ecf20Sopenharmony_ci * 20148c2ecf20Sopenharmony_ci * Return 0 if the name does not exist 20158c2ecf20Sopenharmony_ci * Return -EEXIST if the directory contains the name 20168c2ecf20Sopenharmony_ci * 20178c2ecf20Sopenharmony_ci * Callers should have i_mutex + a cluster lock on dir 20188c2ecf20Sopenharmony_ci */ 20198c2ecf20Sopenharmony_ciint ocfs2_check_dir_for_entry(struct inode *dir, 20208c2ecf20Sopenharmony_ci const char *name, 20218c2ecf20Sopenharmony_ci int namelen) 20228c2ecf20Sopenharmony_ci{ 20238c2ecf20Sopenharmony_ci int ret = 0; 20248c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result lookup = { NULL, }; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci trace_ocfs2_check_dir_for_entry( 20278c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, namelen, name); 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci if (ocfs2_find_entry(name, namelen, dir, &lookup) == 0) { 20308c2ecf20Sopenharmony_ci ret = -EEXIST; 20318c2ecf20Sopenharmony_ci mlog_errno(ret); 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci ocfs2_free_dir_lookup_result(&lookup); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci return ret; 20378c2ecf20Sopenharmony_ci} 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_cistruct ocfs2_empty_dir_priv { 20408c2ecf20Sopenharmony_ci struct dir_context ctx; 20418c2ecf20Sopenharmony_ci unsigned seen_dot; 20428c2ecf20Sopenharmony_ci unsigned seen_dot_dot; 20438c2ecf20Sopenharmony_ci unsigned seen_other; 20448c2ecf20Sopenharmony_ci unsigned dx_dir; 20458c2ecf20Sopenharmony_ci}; 20468c2ecf20Sopenharmony_cistatic int ocfs2_empty_dir_filldir(struct dir_context *ctx, const char *name, 20478c2ecf20Sopenharmony_ci int name_len, loff_t pos, u64 ino, 20488c2ecf20Sopenharmony_ci unsigned type) 20498c2ecf20Sopenharmony_ci{ 20508c2ecf20Sopenharmony_ci struct ocfs2_empty_dir_priv *p = 20518c2ecf20Sopenharmony_ci container_of(ctx, struct ocfs2_empty_dir_priv, ctx); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* 20548c2ecf20Sopenharmony_ci * Check the positions of "." and ".." records to be sure 20558c2ecf20Sopenharmony_ci * they're in the correct place. 20568c2ecf20Sopenharmony_ci * 20578c2ecf20Sopenharmony_ci * Indexed directories don't need to proceed past the first 20588c2ecf20Sopenharmony_ci * two entries, so we end the scan after seeing '..'. Despite 20598c2ecf20Sopenharmony_ci * that, we allow the scan to proceed In the event that we 20608c2ecf20Sopenharmony_ci * have a corrupted indexed directory (no dot or dot dot 20618c2ecf20Sopenharmony_ci * entries). This allows us to double check for existing 20628c2ecf20Sopenharmony_ci * entries which might not have been found in the index. 20638c2ecf20Sopenharmony_ci */ 20648c2ecf20Sopenharmony_ci if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { 20658c2ecf20Sopenharmony_ci p->seen_dot = 1; 20668c2ecf20Sopenharmony_ci return 0; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci if (name_len == 2 && !strncmp("..", name, 2) && 20708c2ecf20Sopenharmony_ci pos == OCFS2_DIR_REC_LEN(1)) { 20718c2ecf20Sopenharmony_ci p->seen_dot_dot = 1; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (p->dx_dir && p->seen_dot) 20748c2ecf20Sopenharmony_ci return 1; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci return 0; 20778c2ecf20Sopenharmony_ci } 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci p->seen_other = 1; 20808c2ecf20Sopenharmony_ci return 1; 20818c2ecf20Sopenharmony_ci} 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic int ocfs2_empty_dir_dx(struct inode *inode, 20848c2ecf20Sopenharmony_ci struct ocfs2_empty_dir_priv *priv) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci int ret; 20878c2ecf20Sopenharmony_ci struct buffer_head *di_bh = NULL; 20888c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 20898c2ecf20Sopenharmony_ci struct ocfs2_dinode *di; 20908c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci priv->dx_dir = 1; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci ret = ocfs2_read_inode_block(inode, &di_bh); 20958c2ecf20Sopenharmony_ci if (ret) { 20968c2ecf20Sopenharmony_ci mlog_errno(ret); 20978c2ecf20Sopenharmony_ci goto out; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci di = (struct ocfs2_dinode *)di_bh->b_data; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_root(inode, di, &dx_root_bh); 21028c2ecf20Sopenharmony_ci if (ret) { 21038c2ecf20Sopenharmony_ci mlog_errno(ret); 21048c2ecf20Sopenharmony_ci goto out; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci if (le32_to_cpu(dx_root->dr_num_entries) != 2) 21098c2ecf20Sopenharmony_ci priv->seen_other = 1; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ciout: 21128c2ecf20Sopenharmony_ci brelse(di_bh); 21138c2ecf20Sopenharmony_ci brelse(dx_root_bh); 21148c2ecf20Sopenharmony_ci return ret; 21158c2ecf20Sopenharmony_ci} 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci/* 21188c2ecf20Sopenharmony_ci * routine to check that the specified directory is empty (for rmdir) 21198c2ecf20Sopenharmony_ci * 21208c2ecf20Sopenharmony_ci * Returns 1 if dir is empty, zero otherwise. 21218c2ecf20Sopenharmony_ci * 21228c2ecf20Sopenharmony_ci * XXX: This is a performance problem for unindexed directories. 21238c2ecf20Sopenharmony_ci */ 21248c2ecf20Sopenharmony_ciint ocfs2_empty_dir(struct inode *inode) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci int ret; 21278c2ecf20Sopenharmony_ci struct ocfs2_empty_dir_priv priv = { 21288c2ecf20Sopenharmony_ci .ctx.actor = ocfs2_empty_dir_filldir, 21298c2ecf20Sopenharmony_ci }; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(inode)) { 21328c2ecf20Sopenharmony_ci ret = ocfs2_empty_dir_dx(inode, &priv); 21338c2ecf20Sopenharmony_ci if (ret) 21348c2ecf20Sopenharmony_ci mlog_errno(ret); 21358c2ecf20Sopenharmony_ci /* 21368c2ecf20Sopenharmony_ci * We still run ocfs2_dir_foreach to get the checks 21378c2ecf20Sopenharmony_ci * for "." and "..". 21388c2ecf20Sopenharmony_ci */ 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci ret = ocfs2_dir_foreach(inode, &priv.ctx); 21428c2ecf20Sopenharmony_ci if (ret) 21438c2ecf20Sopenharmony_ci mlog_errno(ret); 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci if (!priv.seen_dot || !priv.seen_dot_dot) { 21468c2ecf20Sopenharmony_ci mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", 21478c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(inode)->ip_blkno); 21488c2ecf20Sopenharmony_ci /* 21498c2ecf20Sopenharmony_ci * XXX: Is it really safe to allow an unlink to continue? 21508c2ecf20Sopenharmony_ci */ 21518c2ecf20Sopenharmony_ci return 1; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci return !priv.seen_other; 21558c2ecf20Sopenharmony_ci} 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci/* 21588c2ecf20Sopenharmony_ci * Fills "." and ".." dirents in a new directory block. Returns dirent for 21598c2ecf20Sopenharmony_ci * "..", which might be used during creation of a directory with a trailing 21608c2ecf20Sopenharmony_ci * header. It is otherwise safe to ignore the return code. 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_cistatic struct ocfs2_dir_entry *ocfs2_fill_initial_dirents(struct inode *inode, 21638c2ecf20Sopenharmony_ci struct inode *parent, 21648c2ecf20Sopenharmony_ci char *start, 21658c2ecf20Sopenharmony_ci unsigned int size) 21668c2ecf20Sopenharmony_ci{ 21678c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); 21708c2ecf20Sopenharmony_ci de->name_len = 1; 21718c2ecf20Sopenharmony_ci de->rec_len = 21728c2ecf20Sopenharmony_ci cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len)); 21738c2ecf20Sopenharmony_ci strcpy(de->name, "."); 21748c2ecf20Sopenharmony_ci ocfs2_set_de_type(de, S_IFDIR); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len)); 21778c2ecf20Sopenharmony_ci de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno); 21788c2ecf20Sopenharmony_ci de->rec_len = cpu_to_le16(size - OCFS2_DIR_REC_LEN(1)); 21798c2ecf20Sopenharmony_ci de->name_len = 2; 21808c2ecf20Sopenharmony_ci strcpy(de->name, ".."); 21818c2ecf20Sopenharmony_ci ocfs2_set_de_type(de, S_IFDIR); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci return de; 21848c2ecf20Sopenharmony_ci} 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci/* 21878c2ecf20Sopenharmony_ci * This works together with code in ocfs2_mknod_locked() which sets 21888c2ecf20Sopenharmony_ci * the inline-data flag and initializes the inline-data section. 21898c2ecf20Sopenharmony_ci */ 21908c2ecf20Sopenharmony_cistatic int ocfs2_fill_new_dir_id(struct ocfs2_super *osb, 21918c2ecf20Sopenharmony_ci handle_t *handle, 21928c2ecf20Sopenharmony_ci struct inode *parent, 21938c2ecf20Sopenharmony_ci struct inode *inode, 21948c2ecf20Sopenharmony_ci struct buffer_head *di_bh) 21958c2ecf20Sopenharmony_ci{ 21968c2ecf20Sopenharmony_ci int ret; 21978c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 21988c2ecf20Sopenharmony_ci struct ocfs2_inline_data *data = &di->id2.i_data; 21998c2ecf20Sopenharmony_ci unsigned int size = le16_to_cpu(data->id_count); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, 22028c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 22038c2ecf20Sopenharmony_ci if (ret) { 22048c2ecf20Sopenharmony_ci mlog_errno(ret); 22058c2ecf20Sopenharmony_ci goto out; 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci ocfs2_fill_initial_dirents(inode, parent, data->id_data, size); 22098c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, di_bh); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci i_size_write(inode, size); 22128c2ecf20Sopenharmony_ci set_nlink(inode, 2); 22138c2ecf20Sopenharmony_ci inode->i_blocks = ocfs2_inode_sector_count(inode); 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci ret = ocfs2_mark_inode_dirty(handle, inode, di_bh); 22168c2ecf20Sopenharmony_ci if (ret < 0) 22178c2ecf20Sopenharmony_ci mlog_errno(ret); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ciout: 22208c2ecf20Sopenharmony_ci return ret; 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_cistatic int ocfs2_fill_new_dir_el(struct ocfs2_super *osb, 22248c2ecf20Sopenharmony_ci handle_t *handle, 22258c2ecf20Sopenharmony_ci struct inode *parent, 22268c2ecf20Sopenharmony_ci struct inode *inode, 22278c2ecf20Sopenharmony_ci struct buffer_head *fe_bh, 22288c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 22298c2ecf20Sopenharmony_ci struct buffer_head **ret_new_bh) 22308c2ecf20Sopenharmony_ci{ 22318c2ecf20Sopenharmony_ci int status; 22328c2ecf20Sopenharmony_ci unsigned int size = osb->sb->s_blocksize; 22338c2ecf20Sopenharmony_ci struct buffer_head *new_bh = NULL; 22348c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci if (ocfs2_new_dir_wants_trailer(inode)) 22378c2ecf20Sopenharmony_ci size = ocfs2_dir_trailer_blk_off(parent->i_sb); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, 22408c2ecf20Sopenharmony_ci data_ac, NULL, &new_bh); 22418c2ecf20Sopenharmony_ci if (status < 0) { 22428c2ecf20Sopenharmony_ci mlog_errno(status); 22438c2ecf20Sopenharmony_ci goto bail; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), new_bh); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci status = ocfs2_journal_access_db(handle, INODE_CACHE(inode), new_bh, 22498c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 22508c2ecf20Sopenharmony_ci if (status < 0) { 22518c2ecf20Sopenharmony_ci mlog_errno(status); 22528c2ecf20Sopenharmony_ci goto bail; 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci memset(new_bh->b_data, 0, osb->sb->s_blocksize); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci de = ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data, size); 22578c2ecf20Sopenharmony_ci if (ocfs2_new_dir_wants_trailer(inode)) { 22588c2ecf20Sopenharmony_ci int size = le16_to_cpu(de->rec_len); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci /* 22618c2ecf20Sopenharmony_ci * Figure out the size of the hole left over after 22628c2ecf20Sopenharmony_ci * insertion of '.' and '..'. The trailer wants this 22638c2ecf20Sopenharmony_ci * information. 22648c2ecf20Sopenharmony_ci */ 22658c2ecf20Sopenharmony_ci size -= OCFS2_DIR_REC_LEN(2); 22668c2ecf20Sopenharmony_ci size -= sizeof(struct ocfs2_dir_block_trailer); 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci ocfs2_init_dir_trailer(inode, new_bh, size); 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, new_bh); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci i_size_write(inode, inode->i_sb->s_blocksize); 22748c2ecf20Sopenharmony_ci set_nlink(inode, 2); 22758c2ecf20Sopenharmony_ci inode->i_blocks = ocfs2_inode_sector_count(inode); 22768c2ecf20Sopenharmony_ci status = ocfs2_mark_inode_dirty(handle, inode, fe_bh); 22778c2ecf20Sopenharmony_ci if (status < 0) { 22788c2ecf20Sopenharmony_ci mlog_errno(status); 22798c2ecf20Sopenharmony_ci goto bail; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci status = 0; 22838c2ecf20Sopenharmony_ci if (ret_new_bh) { 22848c2ecf20Sopenharmony_ci *ret_new_bh = new_bh; 22858c2ecf20Sopenharmony_ci new_bh = NULL; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_cibail: 22888c2ecf20Sopenharmony_ci brelse(new_bh); 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci return status; 22918c2ecf20Sopenharmony_ci} 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, 22948c2ecf20Sopenharmony_ci handle_t *handle, struct inode *dir, 22958c2ecf20Sopenharmony_ci struct buffer_head *di_bh, 22968c2ecf20Sopenharmony_ci struct buffer_head *dirdata_bh, 22978c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac, 22988c2ecf20Sopenharmony_ci int dx_inline, u32 num_entries, 22998c2ecf20Sopenharmony_ci struct buffer_head **ret_dx_root_bh) 23008c2ecf20Sopenharmony_ci{ 23018c2ecf20Sopenharmony_ci int ret; 23028c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; 23038c2ecf20Sopenharmony_ci u16 dr_suballoc_bit; 23048c2ecf20Sopenharmony_ci u64 suballoc_loc, dr_blkno; 23058c2ecf20Sopenharmony_ci unsigned int num_bits; 23068c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 23078c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 23088c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *trailer = 23098c2ecf20Sopenharmony_ci ocfs2_trailer_from_bh(dirdata_bh, dir->i_sb); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci ret = ocfs2_claim_metadata(handle, meta_ac, 1, &suballoc_loc, 23128c2ecf20Sopenharmony_ci &dr_suballoc_bit, &num_bits, &dr_blkno); 23138c2ecf20Sopenharmony_ci if (ret) { 23148c2ecf20Sopenharmony_ci mlog_errno(ret); 23158c2ecf20Sopenharmony_ci goto out; 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_attach_index( 23198c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, 23208c2ecf20Sopenharmony_ci (unsigned long long)dr_blkno); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci dx_root_bh = sb_getblk(osb->sb, dr_blkno); 23238c2ecf20Sopenharmony_ci if (dx_root_bh == NULL) { 23248c2ecf20Sopenharmony_ci ret = -ENOMEM; 23258c2ecf20Sopenharmony_ci goto out; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), dx_root_bh); 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh, 23308c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 23318c2ecf20Sopenharmony_ci if (ret < 0) { 23328c2ecf20Sopenharmony_ci mlog_errno(ret); 23338c2ecf20Sopenharmony_ci goto out; 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 23378c2ecf20Sopenharmony_ci memset(dx_root, 0, osb->sb->s_blocksize); 23388c2ecf20Sopenharmony_ci strcpy(dx_root->dr_signature, OCFS2_DX_ROOT_SIGNATURE); 23398c2ecf20Sopenharmony_ci dx_root->dr_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot); 23408c2ecf20Sopenharmony_ci dx_root->dr_suballoc_loc = cpu_to_le64(suballoc_loc); 23418c2ecf20Sopenharmony_ci dx_root->dr_suballoc_bit = cpu_to_le16(dr_suballoc_bit); 23428c2ecf20Sopenharmony_ci dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation); 23438c2ecf20Sopenharmony_ci dx_root->dr_blkno = cpu_to_le64(dr_blkno); 23448c2ecf20Sopenharmony_ci dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno); 23458c2ecf20Sopenharmony_ci dx_root->dr_num_entries = cpu_to_le32(num_entries); 23468c2ecf20Sopenharmony_ci if (le16_to_cpu(trailer->db_free_rec_len)) 23478c2ecf20Sopenharmony_ci dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr); 23488c2ecf20Sopenharmony_ci else 23498c2ecf20Sopenharmony_ci dx_root->dr_free_blk = cpu_to_le64(0); 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci if (dx_inline) { 23528c2ecf20Sopenharmony_ci dx_root->dr_flags |= OCFS2_DX_FLAG_INLINE; 23538c2ecf20Sopenharmony_ci dx_root->dr_entries.de_count = 23548c2ecf20Sopenharmony_ci cpu_to_le16(ocfs2_dx_entries_per_root(osb->sb)); 23558c2ecf20Sopenharmony_ci } else { 23568c2ecf20Sopenharmony_ci dx_root->dr_list.l_count = 23578c2ecf20Sopenharmony_ci cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb)); 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_root_bh); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_di(handle, INODE_CACHE(dir), di_bh, 23628c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 23638c2ecf20Sopenharmony_ci if (ret) { 23648c2ecf20Sopenharmony_ci mlog_errno(ret); 23658c2ecf20Sopenharmony_ci goto out; 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci di->i_dx_root = cpu_to_le64(dr_blkno); 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci spin_lock(&OCFS2_I(dir)->ip_lock); 23718c2ecf20Sopenharmony_ci OCFS2_I(dir)->ip_dyn_features |= OCFS2_INDEXED_DIR_FL; 23728c2ecf20Sopenharmony_ci di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features); 23738c2ecf20Sopenharmony_ci spin_unlock(&OCFS2_I(dir)->ip_lock); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, di_bh); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci *ret_dx_root_bh = dx_root_bh; 23788c2ecf20Sopenharmony_ci dx_root_bh = NULL; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ciout: 23818c2ecf20Sopenharmony_ci brelse(dx_root_bh); 23828c2ecf20Sopenharmony_ci return ret; 23838c2ecf20Sopenharmony_ci} 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_format_cluster(struct ocfs2_super *osb, 23868c2ecf20Sopenharmony_ci handle_t *handle, struct inode *dir, 23878c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves, 23888c2ecf20Sopenharmony_ci int num_dx_leaves, u64 start_blk) 23898c2ecf20Sopenharmony_ci{ 23908c2ecf20Sopenharmony_ci int ret, i; 23918c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf; 23928c2ecf20Sopenharmony_ci struct buffer_head *bh; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci for (i = 0; i < num_dx_leaves; i++) { 23958c2ecf20Sopenharmony_ci bh = sb_getblk(osb->sb, start_blk + i); 23968c2ecf20Sopenharmony_ci if (bh == NULL) { 23978c2ecf20Sopenharmony_ci ret = -ENOMEM; 23988c2ecf20Sopenharmony_ci goto out; 23998c2ecf20Sopenharmony_ci } 24008c2ecf20Sopenharmony_ci dx_leaves[i] = bh; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), bh); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), bh, 24058c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 24068c2ecf20Sopenharmony_ci if (ret < 0) { 24078c2ecf20Sopenharmony_ci mlog_errno(ret); 24088c2ecf20Sopenharmony_ci goto out; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci dx_leaf = (struct ocfs2_dx_leaf *) bh->b_data; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci memset(dx_leaf, 0, osb->sb->s_blocksize); 24148c2ecf20Sopenharmony_ci strcpy(dx_leaf->dl_signature, OCFS2_DX_LEAF_SIGNATURE); 24158c2ecf20Sopenharmony_ci dx_leaf->dl_fs_generation = cpu_to_le32(osb->fs_generation); 24168c2ecf20Sopenharmony_ci dx_leaf->dl_blkno = cpu_to_le64(bh->b_blocknr); 24178c2ecf20Sopenharmony_ci dx_leaf->dl_list.de_count = 24188c2ecf20Sopenharmony_ci cpu_to_le16(ocfs2_dx_entries_per_leaf(osb->sb)); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_format_cluster( 24218c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, 24228c2ecf20Sopenharmony_ci (unsigned long long)bh->b_blocknr, 24238c2ecf20Sopenharmony_ci le16_to_cpu(dx_leaf->dl_list.de_count)); 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, bh); 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci ret = 0; 24298c2ecf20Sopenharmony_ciout: 24308c2ecf20Sopenharmony_ci return ret; 24318c2ecf20Sopenharmony_ci} 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci/* 24348c2ecf20Sopenharmony_ci * Allocates and formats a new cluster for use in an indexed dir 24358c2ecf20Sopenharmony_ci * leaf. This version will not do the extent insert, so that it can be 24368c2ecf20Sopenharmony_ci * used by operations which need careful ordering. 24378c2ecf20Sopenharmony_ci */ 24388c2ecf20Sopenharmony_cistatic int __ocfs2_dx_dir_new_cluster(struct inode *dir, 24398c2ecf20Sopenharmony_ci u32 cpos, handle_t *handle, 24408c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 24418c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves, 24428c2ecf20Sopenharmony_ci int num_dx_leaves, u64 *ret_phys_blkno) 24438c2ecf20Sopenharmony_ci{ 24448c2ecf20Sopenharmony_ci int ret; 24458c2ecf20Sopenharmony_ci u32 phys, num; 24468c2ecf20Sopenharmony_ci u64 phys_blkno; 24478c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci /* 24508c2ecf20Sopenharmony_ci * XXX: For create, this should claim cluster for the index 24518c2ecf20Sopenharmony_ci * *before* the unindexed insert so that we have a better 24528c2ecf20Sopenharmony_ci * chance of contiguousness as the directory grows in number 24538c2ecf20Sopenharmony_ci * of entries. 24548c2ecf20Sopenharmony_ci */ 24558c2ecf20Sopenharmony_ci ret = __ocfs2_claim_clusters(handle, data_ac, 1, 1, &phys, &num); 24568c2ecf20Sopenharmony_ci if (ret) { 24578c2ecf20Sopenharmony_ci mlog_errno(ret); 24588c2ecf20Sopenharmony_ci goto out; 24598c2ecf20Sopenharmony_ci } 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci /* 24628c2ecf20Sopenharmony_ci * Format the new cluster first. That way, we're inserting 24638c2ecf20Sopenharmony_ci * valid data. 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_ci phys_blkno = ocfs2_clusters_to_blocks(osb->sb, phys); 24668c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_format_cluster(osb, handle, dir, dx_leaves, 24678c2ecf20Sopenharmony_ci num_dx_leaves, phys_blkno); 24688c2ecf20Sopenharmony_ci if (ret) { 24698c2ecf20Sopenharmony_ci mlog_errno(ret); 24708c2ecf20Sopenharmony_ci goto out; 24718c2ecf20Sopenharmony_ci } 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci *ret_phys_blkno = phys_blkno; 24748c2ecf20Sopenharmony_ciout: 24758c2ecf20Sopenharmony_ci return ret; 24768c2ecf20Sopenharmony_ci} 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_new_cluster(struct inode *dir, 24798c2ecf20Sopenharmony_ci struct ocfs2_extent_tree *et, 24808c2ecf20Sopenharmony_ci u32 cpos, handle_t *handle, 24818c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 24828c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac, 24838c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves, 24848c2ecf20Sopenharmony_ci int num_dx_leaves) 24858c2ecf20Sopenharmony_ci{ 24868c2ecf20Sopenharmony_ci int ret; 24878c2ecf20Sopenharmony_ci u64 phys_blkno; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci ret = __ocfs2_dx_dir_new_cluster(dir, cpos, handle, data_ac, dx_leaves, 24908c2ecf20Sopenharmony_ci num_dx_leaves, &phys_blkno); 24918c2ecf20Sopenharmony_ci if (ret) { 24928c2ecf20Sopenharmony_ci mlog_errno(ret); 24938c2ecf20Sopenharmony_ci goto out; 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci ret = ocfs2_insert_extent(handle, et, cpos, phys_blkno, 1, 0, 24978c2ecf20Sopenharmony_ci meta_ac); 24988c2ecf20Sopenharmony_ci if (ret) 24998c2ecf20Sopenharmony_ci mlog_errno(ret); 25008c2ecf20Sopenharmony_ciout: 25018c2ecf20Sopenharmony_ci return ret; 25028c2ecf20Sopenharmony_ci} 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_cistatic struct buffer_head **ocfs2_dx_dir_kmalloc_leaves(struct super_block *sb, 25058c2ecf20Sopenharmony_ci int *ret_num_leaves) 25068c2ecf20Sopenharmony_ci{ 25078c2ecf20Sopenharmony_ci int num_dx_leaves = ocfs2_clusters_to_blocks(sb, 1); 25088c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci dx_leaves = kcalloc(num_dx_leaves, sizeof(struct buffer_head *), 25118c2ecf20Sopenharmony_ci GFP_NOFS); 25128c2ecf20Sopenharmony_ci if (dx_leaves && ret_num_leaves) 25138c2ecf20Sopenharmony_ci *ret_num_leaves = num_dx_leaves; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci return dx_leaves; 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_cistatic int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb, 25198c2ecf20Sopenharmony_ci handle_t *handle, 25208c2ecf20Sopenharmony_ci struct inode *parent, 25218c2ecf20Sopenharmony_ci struct inode *inode, 25228c2ecf20Sopenharmony_ci struct buffer_head *di_bh, 25238c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 25248c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac) 25258c2ecf20Sopenharmony_ci{ 25268c2ecf20Sopenharmony_ci int ret; 25278c2ecf20Sopenharmony_ci struct buffer_head *leaf_bh = NULL; 25288c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 25298c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo hinfo; 25308c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 25318c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *entry_list; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci /* 25348c2ecf20Sopenharmony_ci * Our strategy is to create the directory as though it were 25358c2ecf20Sopenharmony_ci * unindexed, then add the index block. This works with very 25368c2ecf20Sopenharmony_ci * little complication since the state of a new directory is a 25378c2ecf20Sopenharmony_ci * very well known quantity. 25388c2ecf20Sopenharmony_ci * 25398c2ecf20Sopenharmony_ci * Essentially, we have two dirents ("." and ".."), in the 1st 25408c2ecf20Sopenharmony_ci * block which need indexing. These are easily inserted into 25418c2ecf20Sopenharmony_ci * the index block. 25428c2ecf20Sopenharmony_ci */ 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci ret = ocfs2_fill_new_dir_el(osb, handle, parent, inode, di_bh, 25458c2ecf20Sopenharmony_ci data_ac, &leaf_bh); 25468c2ecf20Sopenharmony_ci if (ret) { 25478c2ecf20Sopenharmony_ci mlog_errno(ret); 25488c2ecf20Sopenharmony_ci goto out; 25498c2ecf20Sopenharmony_ci } 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, leaf_bh, 25528c2ecf20Sopenharmony_ci meta_ac, 1, 2, &dx_root_bh); 25538c2ecf20Sopenharmony_ci if (ret) { 25548c2ecf20Sopenharmony_ci mlog_errno(ret); 25558c2ecf20Sopenharmony_ci goto out; 25568c2ecf20Sopenharmony_ci } 25578c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 25588c2ecf20Sopenharmony_ci entry_list = &dx_root->dr_entries; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci /* Buffer has been journaled for us by ocfs2_dx_dir_attach_index */ 25618c2ecf20Sopenharmony_ci ocfs2_dx_dir_name_hash(inode, ".", 1, &hinfo); 25628c2ecf20Sopenharmony_ci ocfs2_dx_entry_list_insert(entry_list, &hinfo, leaf_bh->b_blocknr); 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci ocfs2_dx_dir_name_hash(inode, "..", 2, &hinfo); 25658c2ecf20Sopenharmony_ci ocfs2_dx_entry_list_insert(entry_list, &hinfo, leaf_bh->b_blocknr); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ciout: 25688c2ecf20Sopenharmony_ci brelse(dx_root_bh); 25698c2ecf20Sopenharmony_ci brelse(leaf_bh); 25708c2ecf20Sopenharmony_ci return ret; 25718c2ecf20Sopenharmony_ci} 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ciint ocfs2_fill_new_dir(struct ocfs2_super *osb, 25748c2ecf20Sopenharmony_ci handle_t *handle, 25758c2ecf20Sopenharmony_ci struct inode *parent, 25768c2ecf20Sopenharmony_ci struct inode *inode, 25778c2ecf20Sopenharmony_ci struct buffer_head *fe_bh, 25788c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 25798c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac) 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci{ 25828c2ecf20Sopenharmony_ci BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) 25858c2ecf20Sopenharmony_ci return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb)) 25888c2ecf20Sopenharmony_ci return ocfs2_fill_new_dir_dx(osb, handle, parent, inode, fe_bh, 25898c2ecf20Sopenharmony_ci data_ac, meta_ac); 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh, 25928c2ecf20Sopenharmony_ci data_ac, NULL); 25938c2ecf20Sopenharmony_ci} 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_index_block(struct inode *dir, 25968c2ecf20Sopenharmony_ci handle_t *handle, 25978c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves, 25988c2ecf20Sopenharmony_ci int num_dx_leaves, 25998c2ecf20Sopenharmony_ci u32 *num_dx_entries, 26008c2ecf20Sopenharmony_ci struct buffer_head *dirent_bh) 26018c2ecf20Sopenharmony_ci{ 26028c2ecf20Sopenharmony_ci int ret = 0, namelen, i; 26038c2ecf20Sopenharmony_ci char *de_buf, *limit; 26048c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 26058c2ecf20Sopenharmony_ci struct buffer_head *dx_leaf_bh; 26068c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo hinfo; 26078c2ecf20Sopenharmony_ci u64 dirent_blk = dirent_bh->b_blocknr; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci de_buf = dirent_bh->b_data; 26108c2ecf20Sopenharmony_ci limit = de_buf + dir->i_sb->s_blocksize; 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci while (de_buf < limit) { 26138c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci namelen = de->name_len; 26168c2ecf20Sopenharmony_ci if (!namelen || !de->inode) 26178c2ecf20Sopenharmony_ci goto inc; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci ocfs2_dx_dir_name_hash(dir, de->name, namelen, &hinfo); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci i = ocfs2_dx_dir_hash_idx(OCFS2_SB(dir->i_sb), &hinfo); 26228c2ecf20Sopenharmony_ci dx_leaf_bh = dx_leaves[i]; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci ret = __ocfs2_dx_dir_leaf_insert(dir, handle, &hinfo, 26258c2ecf20Sopenharmony_ci dirent_blk, dx_leaf_bh); 26268c2ecf20Sopenharmony_ci if (ret) { 26278c2ecf20Sopenharmony_ci mlog_errno(ret); 26288c2ecf20Sopenharmony_ci goto out; 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci *num_dx_entries = *num_dx_entries + 1; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ciinc: 26348c2ecf20Sopenharmony_ci de_buf += le16_to_cpu(de->rec_len); 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ciout: 26388c2ecf20Sopenharmony_ci return ret; 26398c2ecf20Sopenharmony_ci} 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci/* 26428c2ecf20Sopenharmony_ci * XXX: This expects dx_root_bh to already be part of the transaction. 26438c2ecf20Sopenharmony_ci */ 26448c2ecf20Sopenharmony_cistatic void ocfs2_dx_dir_index_root_block(struct inode *dir, 26458c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh, 26468c2ecf20Sopenharmony_ci struct buffer_head *dirent_bh) 26478c2ecf20Sopenharmony_ci{ 26488c2ecf20Sopenharmony_ci char *de_buf, *limit; 26498c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 26508c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 26518c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo hinfo; 26528c2ecf20Sopenharmony_ci u64 dirent_blk = dirent_bh->b_blocknr; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci de_buf = dirent_bh->b_data; 26578c2ecf20Sopenharmony_ci limit = de_buf + dir->i_sb->s_blocksize; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci while (de_buf < limit) { 26608c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci if (!de->name_len || !de->inode) 26638c2ecf20Sopenharmony_ci goto inc; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci ocfs2_dx_dir_name_hash(dir, de->name, de->name_len, &hinfo); 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_index_root_block( 26688c2ecf20Sopenharmony_ci (unsigned long long)dir->i_ino, 26698c2ecf20Sopenharmony_ci hinfo.major_hash, hinfo.minor_hash, 26708c2ecf20Sopenharmony_ci de->name_len, de->name, 26718c2ecf20Sopenharmony_ci le16_to_cpu(dx_root->dr_entries.de_num_used)); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo, 26748c2ecf20Sopenharmony_ci dirent_blk); 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci le32_add_cpu(&dx_root->dr_num_entries, 1); 26778c2ecf20Sopenharmony_ciinc: 26788c2ecf20Sopenharmony_ci de_buf += le16_to_cpu(de->rec_len); 26798c2ecf20Sopenharmony_ci } 26808c2ecf20Sopenharmony_ci} 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci/* 26838c2ecf20Sopenharmony_ci * Count the number of inline directory entries in di_bh and compare 26848c2ecf20Sopenharmony_ci * them against the number of entries we can hold in an inline dx root 26858c2ecf20Sopenharmony_ci * block. 26868c2ecf20Sopenharmony_ci */ 26878c2ecf20Sopenharmony_cistatic int ocfs2_new_dx_should_be_inline(struct inode *dir, 26888c2ecf20Sopenharmony_ci struct buffer_head *di_bh) 26898c2ecf20Sopenharmony_ci{ 26908c2ecf20Sopenharmony_ci int dirent_count = 0; 26918c2ecf20Sopenharmony_ci char *de_buf, *limit; 26928c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 26938c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci de_buf = di->id2.i_data.id_data; 26968c2ecf20Sopenharmony_ci limit = de_buf + i_size_read(dir); 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci while (de_buf < limit) { 26998c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci if (de->name_len && de->inode) 27028c2ecf20Sopenharmony_ci dirent_count++; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci de_buf += le16_to_cpu(de->rec_len); 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci /* We are careful to leave room for one extra record. */ 27088c2ecf20Sopenharmony_ci return dirent_count < ocfs2_dx_entries_per_root(dir->i_sb); 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci/* 27128c2ecf20Sopenharmony_ci * Expand rec_len of the rightmost dirent in a directory block so that it 27138c2ecf20Sopenharmony_ci * contains the end of our valid space for dirents. We do this during 27148c2ecf20Sopenharmony_ci * expansion from an inline directory to one with extents. The first dir block 27158c2ecf20Sopenharmony_ci * in that case is taken from the inline data portion of the inode block. 27168c2ecf20Sopenharmony_ci * 27178c2ecf20Sopenharmony_ci * This will also return the largest amount of contiguous space for a dirent 27188c2ecf20Sopenharmony_ci * in the block. That value is *not* necessarily the last dirent, even after 27198c2ecf20Sopenharmony_ci * expansion. The directory indexing code wants this value for free space 27208c2ecf20Sopenharmony_ci * accounting. We do this here since we're already walking the entire dir 27218c2ecf20Sopenharmony_ci * block. 27228c2ecf20Sopenharmony_ci * 27238c2ecf20Sopenharmony_ci * We add the dir trailer if this filesystem wants it. 27248c2ecf20Sopenharmony_ci */ 27258c2ecf20Sopenharmony_cistatic unsigned int ocfs2_expand_last_dirent(char *start, unsigned int old_size, 27268c2ecf20Sopenharmony_ci struct inode *dir) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 27298c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 27308c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *prev_de; 27318c2ecf20Sopenharmony_ci char *de_buf, *limit; 27328c2ecf20Sopenharmony_ci unsigned int new_size = sb->s_blocksize; 27338c2ecf20Sopenharmony_ci unsigned int bytes, this_hole; 27348c2ecf20Sopenharmony_ci unsigned int largest_hole = 0; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci if (ocfs2_new_dir_wants_trailer(dir)) 27378c2ecf20Sopenharmony_ci new_size = ocfs2_dir_trailer_blk_off(sb); 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci bytes = new_size - old_size; 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci limit = start + old_size; 27428c2ecf20Sopenharmony_ci de_buf = start; 27438c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 27448c2ecf20Sopenharmony_ci do { 27458c2ecf20Sopenharmony_ci this_hole = ocfs2_figure_dirent_hole(de); 27468c2ecf20Sopenharmony_ci if (this_hole > largest_hole) 27478c2ecf20Sopenharmony_ci largest_hole = this_hole; 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci prev_de = de; 27508c2ecf20Sopenharmony_ci de_buf += le16_to_cpu(de->rec_len); 27518c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 27528c2ecf20Sopenharmony_ci } while (de_buf < limit); 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci le16_add_cpu(&prev_de->rec_len, bytes); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci /* We need to double check this after modification of the final 27578c2ecf20Sopenharmony_ci * dirent. */ 27588c2ecf20Sopenharmony_ci this_hole = ocfs2_figure_dirent_hole(prev_de); 27598c2ecf20Sopenharmony_ci if (this_hole > largest_hole) 27608c2ecf20Sopenharmony_ci largest_hole = this_hole; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci if (largest_hole >= OCFS2_DIR_MIN_REC_LEN) 27638c2ecf20Sopenharmony_ci return largest_hole; 27648c2ecf20Sopenharmony_ci return 0; 27658c2ecf20Sopenharmony_ci} 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci/* 27688c2ecf20Sopenharmony_ci * We allocate enough clusters to fulfill "blocks_wanted", but set 27698c2ecf20Sopenharmony_ci * i_size to exactly one block. Ocfs2_extend_dir() will handle the 27708c2ecf20Sopenharmony_ci * rest automatically for us. 27718c2ecf20Sopenharmony_ci * 27728c2ecf20Sopenharmony_ci * *first_block_bh is a pointer to the 1st data block allocated to the 27738c2ecf20Sopenharmony_ci * directory. 27748c2ecf20Sopenharmony_ci */ 27758c2ecf20Sopenharmony_cistatic int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, 27768c2ecf20Sopenharmony_ci unsigned int blocks_wanted, 27778c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup, 27788c2ecf20Sopenharmony_ci struct buffer_head **first_block_bh) 27798c2ecf20Sopenharmony_ci{ 27808c2ecf20Sopenharmony_ci u32 alloc, dx_alloc, bit_off, len, num_dx_entries = 0; 27818c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 27828c2ecf20Sopenharmony_ci int ret, i, num_dx_leaves = 0, dx_inline = 0, 27838c2ecf20Sopenharmony_ci credits = ocfs2_inline_to_extents_credits(sb); 27848c2ecf20Sopenharmony_ci u64 dx_insert_blkno, blkno, 27858c2ecf20Sopenharmony_ci bytes = blocks_wanted << sb->s_blocksize_bits; 27868c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 27878c2ecf20Sopenharmony_ci struct ocfs2_inode_info *oi = OCFS2_I(dir); 27888c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac = NULL; 27898c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac = NULL; 27908c2ecf20Sopenharmony_ci struct buffer_head *dirdata_bh = NULL; 27918c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 27928c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves = NULL; 27938c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 27948c2ecf20Sopenharmony_ci handle_t *handle; 27958c2ecf20Sopenharmony_ci struct ocfs2_extent_tree et; 27968c2ecf20Sopenharmony_ci struct ocfs2_extent_tree dx_et; 27978c2ecf20Sopenharmony_ci int did_quota = 0, bytes_allocated = 0; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(dir), di_bh); 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci alloc = ocfs2_clusters_for_bytes(sb, bytes); 28028c2ecf20Sopenharmony_ci dx_alloc = 0; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci down_write(&oi->ip_alloc_sem); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb)) { 28078c2ecf20Sopenharmony_ci credits += ocfs2_add_dir_index_credits(sb); 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci dx_inline = ocfs2_new_dx_should_be_inline(dir, di_bh); 28108c2ecf20Sopenharmony_ci if (!dx_inline) { 28118c2ecf20Sopenharmony_ci /* Add one more cluster for an index leaf */ 28128c2ecf20Sopenharmony_ci dx_alloc++; 28138c2ecf20Sopenharmony_ci dx_leaves = ocfs2_dx_dir_kmalloc_leaves(sb, 28148c2ecf20Sopenharmony_ci &num_dx_leaves); 28158c2ecf20Sopenharmony_ci if (!dx_leaves) { 28168c2ecf20Sopenharmony_ci ret = -ENOMEM; 28178c2ecf20Sopenharmony_ci mlog_errno(ret); 28188c2ecf20Sopenharmony_ci goto out; 28198c2ecf20Sopenharmony_ci } 28208c2ecf20Sopenharmony_ci } 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci /* This gets us the dx_root */ 28238c2ecf20Sopenharmony_ci ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); 28248c2ecf20Sopenharmony_ci if (ret) { 28258c2ecf20Sopenharmony_ci mlog_errno(ret); 28268c2ecf20Sopenharmony_ci goto out; 28278c2ecf20Sopenharmony_ci } 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci /* 28318c2ecf20Sopenharmony_ci * We should never need more than 2 clusters for the unindexed 28328c2ecf20Sopenharmony_ci * tree - maximum dirent size is far less than one block. In 28338c2ecf20Sopenharmony_ci * fact, the only time we'd need more than one cluster is if 28348c2ecf20Sopenharmony_ci * blocksize == clustersize and the dirent won't fit in the 28358c2ecf20Sopenharmony_ci * extra space that the expansion to a single block gives. As 28368c2ecf20Sopenharmony_ci * of today, that only happens on 4k/4k file systems. 28378c2ecf20Sopenharmony_ci */ 28388c2ecf20Sopenharmony_ci BUG_ON(alloc > 2); 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci ret = ocfs2_reserve_clusters(osb, alloc + dx_alloc, &data_ac); 28418c2ecf20Sopenharmony_ci if (ret) { 28428c2ecf20Sopenharmony_ci mlog_errno(ret); 28438c2ecf20Sopenharmony_ci goto out; 28448c2ecf20Sopenharmony_ci } 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci /* 28478c2ecf20Sopenharmony_ci * Prepare for worst case allocation scenario of two separate 28488c2ecf20Sopenharmony_ci * extents in the unindexed tree. 28498c2ecf20Sopenharmony_ci */ 28508c2ecf20Sopenharmony_ci if (alloc == 2) 28518c2ecf20Sopenharmony_ci credits += OCFS2_SUBALLOC_ALLOC; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci handle = ocfs2_start_trans(osb, credits); 28548c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 28558c2ecf20Sopenharmony_ci ret = PTR_ERR(handle); 28568c2ecf20Sopenharmony_ci mlog_errno(ret); 28578c2ecf20Sopenharmony_ci goto out; 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci ret = dquot_alloc_space_nodirty(dir, 28618c2ecf20Sopenharmony_ci ocfs2_clusters_to_bytes(osb->sb, alloc + dx_alloc)); 28628c2ecf20Sopenharmony_ci if (ret) 28638c2ecf20Sopenharmony_ci goto out_commit; 28648c2ecf20Sopenharmony_ci did_quota = 1; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) { 28678c2ecf20Sopenharmony_ci /* 28688c2ecf20Sopenharmony_ci * Allocate our index cluster first, to maximize the 28698c2ecf20Sopenharmony_ci * possibility that unindexed leaves grow 28708c2ecf20Sopenharmony_ci * contiguously. 28718c2ecf20Sopenharmony_ci */ 28728c2ecf20Sopenharmony_ci ret = __ocfs2_dx_dir_new_cluster(dir, 0, handle, data_ac, 28738c2ecf20Sopenharmony_ci dx_leaves, num_dx_leaves, 28748c2ecf20Sopenharmony_ci &dx_insert_blkno); 28758c2ecf20Sopenharmony_ci if (ret) { 28768c2ecf20Sopenharmony_ci mlog_errno(ret); 28778c2ecf20Sopenharmony_ci goto out_commit; 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci bytes_allocated += ocfs2_clusters_to_bytes(dir->i_sb, 1); 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci /* 28838c2ecf20Sopenharmony_ci * Try to claim as many clusters as the bitmap can give though 28848c2ecf20Sopenharmony_ci * if we only get one now, that's enough to continue. The rest 28858c2ecf20Sopenharmony_ci * will be claimed after the conversion to extents. 28868c2ecf20Sopenharmony_ci */ 28878c2ecf20Sopenharmony_ci if (ocfs2_dir_resv_allowed(osb)) 28888c2ecf20Sopenharmony_ci data_ac->ac_resv = &oi->ip_la_data_resv; 28898c2ecf20Sopenharmony_ci ret = ocfs2_claim_clusters(handle, data_ac, 1, &bit_off, &len); 28908c2ecf20Sopenharmony_ci if (ret) { 28918c2ecf20Sopenharmony_ci mlog_errno(ret); 28928c2ecf20Sopenharmony_ci goto out_commit; 28938c2ecf20Sopenharmony_ci } 28948c2ecf20Sopenharmony_ci bytes_allocated += ocfs2_clusters_to_bytes(dir->i_sb, 1); 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci /* 28978c2ecf20Sopenharmony_ci * Operations are carefully ordered so that we set up the new 28988c2ecf20Sopenharmony_ci * data block first. The conversion from inline data to 28998c2ecf20Sopenharmony_ci * extents follows. 29008c2ecf20Sopenharmony_ci */ 29018c2ecf20Sopenharmony_ci blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); 29028c2ecf20Sopenharmony_ci dirdata_bh = sb_getblk(sb, blkno); 29038c2ecf20Sopenharmony_ci if (!dirdata_bh) { 29048c2ecf20Sopenharmony_ci ret = -ENOMEM; 29058c2ecf20Sopenharmony_ci mlog_errno(ret); 29068c2ecf20Sopenharmony_ci goto out_commit; 29078c2ecf20Sopenharmony_ci } 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), dirdata_bh); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_db(handle, INODE_CACHE(dir), dirdata_bh, 29128c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 29138c2ecf20Sopenharmony_ci if (ret) { 29148c2ecf20Sopenharmony_ci mlog_errno(ret); 29158c2ecf20Sopenharmony_ci goto out_commit; 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir)); 29198c2ecf20Sopenharmony_ci memset(dirdata_bh->b_data + i_size_read(dir), 0, 29208c2ecf20Sopenharmony_ci sb->s_blocksize - i_size_read(dir)); 29218c2ecf20Sopenharmony_ci i = ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), dir); 29228c2ecf20Sopenharmony_ci if (ocfs2_new_dir_wants_trailer(dir)) { 29238c2ecf20Sopenharmony_ci /* 29248c2ecf20Sopenharmony_ci * Prepare the dir trailer up front. It will otherwise look 29258c2ecf20Sopenharmony_ci * like a valid dirent. Even if inserting the index fails 29268c2ecf20Sopenharmony_ci * (unlikely), then all we'll have done is given first dir 29278c2ecf20Sopenharmony_ci * block a small amount of fragmentation. 29288c2ecf20Sopenharmony_ci */ 29298c2ecf20Sopenharmony_ci ocfs2_init_dir_trailer(dir, dirdata_bh, i); 29308c2ecf20Sopenharmony_ci } 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci ocfs2_update_inode_fsync_trans(handle, dir, 1); 29338c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dirdata_bh); 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) { 29368c2ecf20Sopenharmony_ci /* 29378c2ecf20Sopenharmony_ci * Dx dirs with an external cluster need to do this up 29388c2ecf20Sopenharmony_ci * front. Inline dx root's get handled later, after 29398c2ecf20Sopenharmony_ci * we've allocated our root block. We get passed back 29408c2ecf20Sopenharmony_ci * a total number of items so that dr_num_entries can 29418c2ecf20Sopenharmony_ci * be correctly set once the dx_root has been 29428c2ecf20Sopenharmony_ci * allocated. 29438c2ecf20Sopenharmony_ci */ 29448c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves, 29458c2ecf20Sopenharmony_ci num_dx_leaves, &num_dx_entries, 29468c2ecf20Sopenharmony_ci dirdata_bh); 29478c2ecf20Sopenharmony_ci if (ret) { 29488c2ecf20Sopenharmony_ci mlog_errno(ret); 29498c2ecf20Sopenharmony_ci goto out_commit; 29508c2ecf20Sopenharmony_ci } 29518c2ecf20Sopenharmony_ci } 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci /* 29548c2ecf20Sopenharmony_ci * Set extent, i_size, etc on the directory. After this, the 29558c2ecf20Sopenharmony_ci * inode should contain the same exact dirents as before and 29568c2ecf20Sopenharmony_ci * be fully accessible from system calls. 29578c2ecf20Sopenharmony_ci * 29588c2ecf20Sopenharmony_ci * We let the later dirent insert modify c/mtime - to the user 29598c2ecf20Sopenharmony_ci * the data hasn't changed. 29608c2ecf20Sopenharmony_ci */ 29618c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_di(handle, INODE_CACHE(dir), di_bh, 29628c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 29638c2ecf20Sopenharmony_ci if (ret) { 29648c2ecf20Sopenharmony_ci mlog_errno(ret); 29658c2ecf20Sopenharmony_ci goto out_commit; 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci spin_lock(&oi->ip_lock); 29698c2ecf20Sopenharmony_ci oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL; 29708c2ecf20Sopenharmony_ci di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); 29718c2ecf20Sopenharmony_ci spin_unlock(&oi->ip_lock); 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci ocfs2_dinode_new_extent_list(dir, di); 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci i_size_write(dir, sb->s_blocksize); 29768c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = current_time(dir); 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci di->i_size = cpu_to_le64(sb->s_blocksize); 29798c2ecf20Sopenharmony_ci di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec); 29808c2ecf20Sopenharmony_ci di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec); 29818c2ecf20Sopenharmony_ci ocfs2_update_inode_fsync_trans(handle, dir, 1); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci /* 29848c2ecf20Sopenharmony_ci * This should never fail as our extent list is empty and all 29858c2ecf20Sopenharmony_ci * related blocks have been journaled already. 29868c2ecf20Sopenharmony_ci */ 29878c2ecf20Sopenharmony_ci ret = ocfs2_insert_extent(handle, &et, 0, blkno, len, 29888c2ecf20Sopenharmony_ci 0, NULL); 29898c2ecf20Sopenharmony_ci if (ret) { 29908c2ecf20Sopenharmony_ci mlog_errno(ret); 29918c2ecf20Sopenharmony_ci goto out_commit; 29928c2ecf20Sopenharmony_ci } 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci /* 29958c2ecf20Sopenharmony_ci * Set i_blocks after the extent insert for the most up to 29968c2ecf20Sopenharmony_ci * date ip_clusters value. 29978c2ecf20Sopenharmony_ci */ 29988c2ecf20Sopenharmony_ci dir->i_blocks = ocfs2_inode_sector_count(dir); 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, di_bh); 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb)) { 30038c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh, 30048c2ecf20Sopenharmony_ci dirdata_bh, meta_ac, dx_inline, 30058c2ecf20Sopenharmony_ci num_dx_entries, &dx_root_bh); 30068c2ecf20Sopenharmony_ci if (ret) { 30078c2ecf20Sopenharmony_ci mlog_errno(ret); 30088c2ecf20Sopenharmony_ci goto out_commit; 30098c2ecf20Sopenharmony_ci } 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci if (dx_inline) { 30128c2ecf20Sopenharmony_ci ocfs2_dx_dir_index_root_block(dir, dx_root_bh, 30138c2ecf20Sopenharmony_ci dirdata_bh); 30148c2ecf20Sopenharmony_ci } else { 30158c2ecf20Sopenharmony_ci ocfs2_init_dx_root_extent_tree(&dx_et, 30168c2ecf20Sopenharmony_ci INODE_CACHE(dir), 30178c2ecf20Sopenharmony_ci dx_root_bh); 30188c2ecf20Sopenharmony_ci ret = ocfs2_insert_extent(handle, &dx_et, 0, 30198c2ecf20Sopenharmony_ci dx_insert_blkno, 1, 0, NULL); 30208c2ecf20Sopenharmony_ci if (ret) 30218c2ecf20Sopenharmony_ci mlog_errno(ret); 30228c2ecf20Sopenharmony_ci } 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci /* 30268c2ecf20Sopenharmony_ci * We asked for two clusters, but only got one in the 1st 30278c2ecf20Sopenharmony_ci * pass. Claim the 2nd cluster as a separate extent. 30288c2ecf20Sopenharmony_ci */ 30298c2ecf20Sopenharmony_ci if (alloc > len) { 30308c2ecf20Sopenharmony_ci ret = ocfs2_claim_clusters(handle, data_ac, 1, &bit_off, 30318c2ecf20Sopenharmony_ci &len); 30328c2ecf20Sopenharmony_ci if (ret) { 30338c2ecf20Sopenharmony_ci mlog_errno(ret); 30348c2ecf20Sopenharmony_ci goto out_commit; 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci ret = ocfs2_insert_extent(handle, &et, 1, 30398c2ecf20Sopenharmony_ci blkno, len, 0, NULL); 30408c2ecf20Sopenharmony_ci if (ret) { 30418c2ecf20Sopenharmony_ci mlog_errno(ret); 30428c2ecf20Sopenharmony_ci goto out_commit; 30438c2ecf20Sopenharmony_ci } 30448c2ecf20Sopenharmony_ci bytes_allocated += ocfs2_clusters_to_bytes(dir->i_sb, 1); 30458c2ecf20Sopenharmony_ci } 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci *first_block_bh = dirdata_bh; 30488c2ecf20Sopenharmony_ci dirdata_bh = NULL; 30498c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb)) { 30508c2ecf20Sopenharmony_ci unsigned int off; 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci if (!dx_inline) { 30538c2ecf20Sopenharmony_ci /* 30548c2ecf20Sopenharmony_ci * We need to return the correct block within the 30558c2ecf20Sopenharmony_ci * cluster which should hold our entry. 30568c2ecf20Sopenharmony_ci */ 30578c2ecf20Sopenharmony_ci off = ocfs2_dx_dir_hash_idx(osb, 30588c2ecf20Sopenharmony_ci &lookup->dl_hinfo); 30598c2ecf20Sopenharmony_ci get_bh(dx_leaves[off]); 30608c2ecf20Sopenharmony_ci lookup->dl_dx_leaf_bh = dx_leaves[off]; 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci lookup->dl_dx_root_bh = dx_root_bh; 30638c2ecf20Sopenharmony_ci dx_root_bh = NULL; 30648c2ecf20Sopenharmony_ci } 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ciout_commit: 30678c2ecf20Sopenharmony_ci if (ret < 0 && did_quota) 30688c2ecf20Sopenharmony_ci dquot_free_space_nodirty(dir, bytes_allocated); 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci ocfs2_commit_trans(osb, handle); 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ciout: 30738c2ecf20Sopenharmony_ci up_write(&oi->ip_alloc_sem); 30748c2ecf20Sopenharmony_ci if (data_ac) 30758c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(data_ac); 30768c2ecf20Sopenharmony_ci if (meta_ac) 30778c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(meta_ac); 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci if (dx_leaves) { 30808c2ecf20Sopenharmony_ci for (i = 0; i < num_dx_leaves; i++) 30818c2ecf20Sopenharmony_ci brelse(dx_leaves[i]); 30828c2ecf20Sopenharmony_ci kfree(dx_leaves); 30838c2ecf20Sopenharmony_ci } 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci brelse(dirdata_bh); 30868c2ecf20Sopenharmony_ci brelse(dx_root_bh); 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci return ret; 30898c2ecf20Sopenharmony_ci} 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci/* returns a bh of the 1st new block in the allocation. */ 30928c2ecf20Sopenharmony_cistatic int ocfs2_do_extend_dir(struct super_block *sb, 30938c2ecf20Sopenharmony_ci handle_t *handle, 30948c2ecf20Sopenharmony_ci struct inode *dir, 30958c2ecf20Sopenharmony_ci struct buffer_head *parent_fe_bh, 30968c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac, 30978c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac, 30988c2ecf20Sopenharmony_ci struct buffer_head **new_bh) 30998c2ecf20Sopenharmony_ci{ 31008c2ecf20Sopenharmony_ci int status; 31018c2ecf20Sopenharmony_ci int extend, did_quota = 0; 31028c2ecf20Sopenharmony_ci u64 p_blkno, v_blkno; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci spin_lock(&OCFS2_I(dir)->ip_lock); 31058c2ecf20Sopenharmony_ci extend = (i_size_read(dir) == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)); 31068c2ecf20Sopenharmony_ci spin_unlock(&OCFS2_I(dir)->ip_lock); 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci if (extend) { 31098c2ecf20Sopenharmony_ci u32 offset = OCFS2_I(dir)->ip_clusters; 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci status = dquot_alloc_space_nodirty(dir, 31128c2ecf20Sopenharmony_ci ocfs2_clusters_to_bytes(sb, 1)); 31138c2ecf20Sopenharmony_ci if (status) 31148c2ecf20Sopenharmony_ci goto bail; 31158c2ecf20Sopenharmony_ci did_quota = 1; 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset, 31188c2ecf20Sopenharmony_ci 1, 0, parent_fe_bh, handle, 31198c2ecf20Sopenharmony_ci data_ac, meta_ac, NULL); 31208c2ecf20Sopenharmony_ci BUG_ON(status == -EAGAIN); 31218c2ecf20Sopenharmony_ci if (status < 0) { 31228c2ecf20Sopenharmony_ci mlog_errno(status); 31238c2ecf20Sopenharmony_ci goto bail; 31248c2ecf20Sopenharmony_ci } 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci v_blkno = ocfs2_blocks_for_bytes(sb, i_size_read(dir)); 31288c2ecf20Sopenharmony_ci status = ocfs2_extent_map_get_blocks(dir, v_blkno, &p_blkno, NULL, NULL); 31298c2ecf20Sopenharmony_ci if (status < 0) { 31308c2ecf20Sopenharmony_ci mlog_errno(status); 31318c2ecf20Sopenharmony_ci goto bail; 31328c2ecf20Sopenharmony_ci } 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci *new_bh = sb_getblk(sb, p_blkno); 31358c2ecf20Sopenharmony_ci if (!*new_bh) { 31368c2ecf20Sopenharmony_ci status = -ENOMEM; 31378c2ecf20Sopenharmony_ci mlog_errno(status); 31388c2ecf20Sopenharmony_ci goto bail; 31398c2ecf20Sopenharmony_ci } 31408c2ecf20Sopenharmony_ci status = 0; 31418c2ecf20Sopenharmony_cibail: 31428c2ecf20Sopenharmony_ci if (did_quota && status < 0) 31438c2ecf20Sopenharmony_ci dquot_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1)); 31448c2ecf20Sopenharmony_ci return status; 31458c2ecf20Sopenharmony_ci} 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci/* 31488c2ecf20Sopenharmony_ci * Assumes you already have a cluster lock on the directory. 31498c2ecf20Sopenharmony_ci * 31508c2ecf20Sopenharmony_ci * 'blocks_wanted' is only used if we have an inline directory which 31518c2ecf20Sopenharmony_ci * is to be turned into an extent based one. The size of the dirent to 31528c2ecf20Sopenharmony_ci * insert might be larger than the space gained by growing to just one 31538c2ecf20Sopenharmony_ci * block, so we may have to grow the inode by two blocks in that case. 31548c2ecf20Sopenharmony_ci * 31558c2ecf20Sopenharmony_ci * If the directory is already indexed, dx_root_bh must be provided. 31568c2ecf20Sopenharmony_ci */ 31578c2ecf20Sopenharmony_cistatic int ocfs2_extend_dir(struct ocfs2_super *osb, 31588c2ecf20Sopenharmony_ci struct inode *dir, 31598c2ecf20Sopenharmony_ci struct buffer_head *parent_fe_bh, 31608c2ecf20Sopenharmony_ci unsigned int blocks_wanted, 31618c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup, 31628c2ecf20Sopenharmony_ci struct buffer_head **new_de_bh) 31638c2ecf20Sopenharmony_ci{ 31648c2ecf20Sopenharmony_ci int status = 0; 31658c2ecf20Sopenharmony_ci int credits, num_free_extents, drop_alloc_sem = 0; 31668c2ecf20Sopenharmony_ci loff_t dir_i_size; 31678c2ecf20Sopenharmony_ci struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data; 31688c2ecf20Sopenharmony_ci struct ocfs2_extent_list *el = &fe->id2.i_list; 31698c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac = NULL; 31708c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *meta_ac = NULL; 31718c2ecf20Sopenharmony_ci handle_t *handle = NULL; 31728c2ecf20Sopenharmony_ci struct buffer_head *new_bh = NULL; 31738c2ecf20Sopenharmony_ci struct ocfs2_dir_entry * de; 31748c2ecf20Sopenharmony_ci struct super_block *sb = osb->sb; 31758c2ecf20Sopenharmony_ci struct ocfs2_extent_tree et; 31768c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { 31798c2ecf20Sopenharmony_ci /* 31808c2ecf20Sopenharmony_ci * This would be a code error as an inline directory should 31818c2ecf20Sopenharmony_ci * never have an index root. 31828c2ecf20Sopenharmony_ci */ 31838c2ecf20Sopenharmony_ci BUG_ON(dx_root_bh); 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci status = ocfs2_expand_inline_dir(dir, parent_fe_bh, 31868c2ecf20Sopenharmony_ci blocks_wanted, lookup, 31878c2ecf20Sopenharmony_ci &new_bh); 31888c2ecf20Sopenharmony_ci if (status) { 31898c2ecf20Sopenharmony_ci mlog_errno(status); 31908c2ecf20Sopenharmony_ci goto bail; 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci /* Expansion from inline to an indexed directory will 31948c2ecf20Sopenharmony_ci * have given us this. */ 31958c2ecf20Sopenharmony_ci dx_root_bh = lookup->dl_dx_root_bh; 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci if (blocks_wanted == 1) { 31988c2ecf20Sopenharmony_ci /* 31998c2ecf20Sopenharmony_ci * If the new dirent will fit inside the space 32008c2ecf20Sopenharmony_ci * created by pushing out to one block, then 32018c2ecf20Sopenharmony_ci * we can complete the operation 32028c2ecf20Sopenharmony_ci * here. Otherwise we have to expand i_size 32038c2ecf20Sopenharmony_ci * and format the 2nd block below. 32048c2ecf20Sopenharmony_ci */ 32058c2ecf20Sopenharmony_ci BUG_ON(new_bh == NULL); 32068c2ecf20Sopenharmony_ci goto bail_bh; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci /* 32108c2ecf20Sopenharmony_ci * Get rid of 'new_bh' - we want to format the 2nd 32118c2ecf20Sopenharmony_ci * data block and return that instead. 32128c2ecf20Sopenharmony_ci */ 32138c2ecf20Sopenharmony_ci brelse(new_bh); 32148c2ecf20Sopenharmony_ci new_bh = NULL; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci down_write(&OCFS2_I(dir)->ip_alloc_sem); 32178c2ecf20Sopenharmony_ci drop_alloc_sem = 1; 32188c2ecf20Sopenharmony_ci dir_i_size = i_size_read(dir); 32198c2ecf20Sopenharmony_ci credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; 32208c2ecf20Sopenharmony_ci goto do_extend; 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci down_write(&OCFS2_I(dir)->ip_alloc_sem); 32248c2ecf20Sopenharmony_ci drop_alloc_sem = 1; 32258c2ecf20Sopenharmony_ci dir_i_size = i_size_read(dir); 32268c2ecf20Sopenharmony_ci trace_ocfs2_extend_dir((unsigned long long)OCFS2_I(dir)->ip_blkno, 32278c2ecf20Sopenharmony_ci dir_i_size); 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci /* dir->i_size is always block aligned. */ 32308c2ecf20Sopenharmony_ci spin_lock(&OCFS2_I(dir)->ip_lock); 32318c2ecf20Sopenharmony_ci if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) { 32328c2ecf20Sopenharmony_ci spin_unlock(&OCFS2_I(dir)->ip_lock); 32338c2ecf20Sopenharmony_ci ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(dir), 32348c2ecf20Sopenharmony_ci parent_fe_bh); 32358c2ecf20Sopenharmony_ci num_free_extents = ocfs2_num_free_extents(&et); 32368c2ecf20Sopenharmony_ci if (num_free_extents < 0) { 32378c2ecf20Sopenharmony_ci status = num_free_extents; 32388c2ecf20Sopenharmony_ci mlog_errno(status); 32398c2ecf20Sopenharmony_ci goto bail; 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci if (!num_free_extents) { 32438c2ecf20Sopenharmony_ci status = ocfs2_reserve_new_metadata(osb, el, &meta_ac); 32448c2ecf20Sopenharmony_ci if (status < 0) { 32458c2ecf20Sopenharmony_ci if (status != -ENOSPC) 32468c2ecf20Sopenharmony_ci mlog_errno(status); 32478c2ecf20Sopenharmony_ci goto bail; 32488c2ecf20Sopenharmony_ci } 32498c2ecf20Sopenharmony_ci } 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci status = ocfs2_reserve_clusters(osb, 1, &data_ac); 32528c2ecf20Sopenharmony_ci if (status < 0) { 32538c2ecf20Sopenharmony_ci if (status != -ENOSPC) 32548c2ecf20Sopenharmony_ci mlog_errno(status); 32558c2ecf20Sopenharmony_ci goto bail; 32568c2ecf20Sopenharmony_ci } 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci if (ocfs2_dir_resv_allowed(osb)) 32598c2ecf20Sopenharmony_ci data_ac->ac_resv = &OCFS2_I(dir)->ip_la_data_resv; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci credits = ocfs2_calc_extend_credits(sb, el); 32628c2ecf20Sopenharmony_ci } else { 32638c2ecf20Sopenharmony_ci spin_unlock(&OCFS2_I(dir)->ip_lock); 32648c2ecf20Sopenharmony_ci credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; 32658c2ecf20Sopenharmony_ci } 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_cido_extend: 32688c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) 32698c2ecf20Sopenharmony_ci credits++; /* For attaching the new dirent block to the 32708c2ecf20Sopenharmony_ci * dx_root */ 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci handle = ocfs2_start_trans(osb, credits); 32738c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 32748c2ecf20Sopenharmony_ci status = PTR_ERR(handle); 32758c2ecf20Sopenharmony_ci handle = NULL; 32768c2ecf20Sopenharmony_ci mlog_errno(status); 32778c2ecf20Sopenharmony_ci goto bail; 32788c2ecf20Sopenharmony_ci } 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci status = ocfs2_do_extend_dir(osb->sb, handle, dir, parent_fe_bh, 32818c2ecf20Sopenharmony_ci data_ac, meta_ac, &new_bh); 32828c2ecf20Sopenharmony_ci if (status < 0) { 32838c2ecf20Sopenharmony_ci mlog_errno(status); 32848c2ecf20Sopenharmony_ci goto bail; 32858c2ecf20Sopenharmony_ci } 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), new_bh); 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci status = ocfs2_journal_access_db(handle, INODE_CACHE(dir), new_bh, 32908c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_CREATE); 32918c2ecf20Sopenharmony_ci if (status < 0) { 32928c2ecf20Sopenharmony_ci mlog_errno(status); 32938c2ecf20Sopenharmony_ci goto bail; 32948c2ecf20Sopenharmony_ci } 32958c2ecf20Sopenharmony_ci memset(new_bh->b_data, 0, sb->s_blocksize); 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) new_bh->b_data; 32988c2ecf20Sopenharmony_ci de->inode = 0; 32998c2ecf20Sopenharmony_ci if (ocfs2_supports_dir_trailer(dir)) { 33008c2ecf20Sopenharmony_ci de->rec_len = cpu_to_le16(ocfs2_dir_trailer_blk_off(sb)); 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci ocfs2_init_dir_trailer(dir, new_bh, le16_to_cpu(de->rec_len)); 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) { 33058c2ecf20Sopenharmony_ci status = ocfs2_dx_dir_link_trailer(dir, handle, 33068c2ecf20Sopenharmony_ci dx_root_bh, new_bh); 33078c2ecf20Sopenharmony_ci if (status) { 33088c2ecf20Sopenharmony_ci mlog_errno(status); 33098c2ecf20Sopenharmony_ci goto bail; 33108c2ecf20Sopenharmony_ci } 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci } else { 33138c2ecf20Sopenharmony_ci de->rec_len = cpu_to_le16(sb->s_blocksize); 33148c2ecf20Sopenharmony_ci } 33158c2ecf20Sopenharmony_ci ocfs2_update_inode_fsync_trans(handle, dir, 1); 33168c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, new_bh); 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci dir_i_size += dir->i_sb->s_blocksize; 33198c2ecf20Sopenharmony_ci i_size_write(dir, dir_i_size); 33208c2ecf20Sopenharmony_ci dir->i_blocks = ocfs2_inode_sector_count(dir); 33218c2ecf20Sopenharmony_ci status = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); 33228c2ecf20Sopenharmony_ci if (status < 0) { 33238c2ecf20Sopenharmony_ci mlog_errno(status); 33248c2ecf20Sopenharmony_ci goto bail; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_cibail_bh: 33288c2ecf20Sopenharmony_ci *new_de_bh = new_bh; 33298c2ecf20Sopenharmony_ci get_bh(*new_de_bh); 33308c2ecf20Sopenharmony_cibail: 33318c2ecf20Sopenharmony_ci if (handle) 33328c2ecf20Sopenharmony_ci ocfs2_commit_trans(osb, handle); 33338c2ecf20Sopenharmony_ci if (drop_alloc_sem) 33348c2ecf20Sopenharmony_ci up_write(&OCFS2_I(dir)->ip_alloc_sem); 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci if (data_ac) 33378c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(data_ac); 33388c2ecf20Sopenharmony_ci if (meta_ac) 33398c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(meta_ac); 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci brelse(new_bh); 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci return status; 33448c2ecf20Sopenharmony_ci} 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_cistatic int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, 33478c2ecf20Sopenharmony_ci const char *name, int namelen, 33488c2ecf20Sopenharmony_ci struct buffer_head **ret_de_bh, 33498c2ecf20Sopenharmony_ci unsigned int *blocks_wanted) 33508c2ecf20Sopenharmony_ci{ 33518c2ecf20Sopenharmony_ci int ret; 33528c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 33538c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 33548c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de, *last_de = NULL; 33558c2ecf20Sopenharmony_ci char *first_de, *de_buf, *limit; 33568c2ecf20Sopenharmony_ci unsigned long offset = 0; 33578c2ecf20Sopenharmony_ci unsigned int rec_len, new_rec_len, free_space = dir->i_sb->s_blocksize; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci /* 33608c2ecf20Sopenharmony_ci * This calculates how many free bytes we'd have in block zero, should 33618c2ecf20Sopenharmony_ci * this function force expansion to an extent tree. 33628c2ecf20Sopenharmony_ci */ 33638c2ecf20Sopenharmony_ci if (ocfs2_new_dir_wants_trailer(dir)) 33648c2ecf20Sopenharmony_ci free_space = ocfs2_dir_trailer_blk_off(sb) - i_size_read(dir); 33658c2ecf20Sopenharmony_ci else 33668c2ecf20Sopenharmony_ci free_space = dir->i_sb->s_blocksize - i_size_read(dir); 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci first_de = di->id2.i_data.id_data; 33698c2ecf20Sopenharmony_ci de_buf = first_de; 33708c2ecf20Sopenharmony_ci limit = de_buf + i_size_read(dir); 33718c2ecf20Sopenharmony_ci rec_len = OCFS2_DIR_REC_LEN(namelen); 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci while (de_buf < limit) { 33748c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)de_buf; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(dir, de, di_bh, first_de, 33778c2ecf20Sopenharmony_ci i_size_read(dir), offset)) { 33788c2ecf20Sopenharmony_ci ret = -ENOENT; 33798c2ecf20Sopenharmony_ci goto out; 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci if (ocfs2_match(namelen, name, de)) { 33828c2ecf20Sopenharmony_ci ret = -EEXIST; 33838c2ecf20Sopenharmony_ci goto out; 33848c2ecf20Sopenharmony_ci } 33858c2ecf20Sopenharmony_ci /* 33868c2ecf20Sopenharmony_ci * No need to check for a trailing dirent record here as 33878c2ecf20Sopenharmony_ci * they're not used for inline dirs. 33888c2ecf20Sopenharmony_ci */ 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci if (ocfs2_dirent_would_fit(de, rec_len)) { 33918c2ecf20Sopenharmony_ci /* Ok, we found a spot. Return this bh and let 33928c2ecf20Sopenharmony_ci * the caller actually fill it in. */ 33938c2ecf20Sopenharmony_ci *ret_de_bh = di_bh; 33948c2ecf20Sopenharmony_ci get_bh(*ret_de_bh); 33958c2ecf20Sopenharmony_ci ret = 0; 33968c2ecf20Sopenharmony_ci goto out; 33978c2ecf20Sopenharmony_ci } 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci last_de = de; 34008c2ecf20Sopenharmony_ci de_buf += le16_to_cpu(de->rec_len); 34018c2ecf20Sopenharmony_ci offset += le16_to_cpu(de->rec_len); 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci /* 34058c2ecf20Sopenharmony_ci * We're going to require expansion of the directory - figure 34068c2ecf20Sopenharmony_ci * out how many blocks we'll need so that a place for the 34078c2ecf20Sopenharmony_ci * dirent can be found. 34088c2ecf20Sopenharmony_ci */ 34098c2ecf20Sopenharmony_ci *blocks_wanted = 1; 34108c2ecf20Sopenharmony_ci new_rec_len = le16_to_cpu(last_de->rec_len) + free_space; 34118c2ecf20Sopenharmony_ci if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len))) 34128c2ecf20Sopenharmony_ci *blocks_wanted = 2; 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci ret = -ENOSPC; 34158c2ecf20Sopenharmony_ciout: 34168c2ecf20Sopenharmony_ci return ret; 34178c2ecf20Sopenharmony_ci} 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_cistatic int ocfs2_find_dir_space_el(struct inode *dir, const char *name, 34208c2ecf20Sopenharmony_ci int namelen, struct buffer_head **ret_de_bh) 34218c2ecf20Sopenharmony_ci{ 34228c2ecf20Sopenharmony_ci unsigned long offset; 34238c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 34248c2ecf20Sopenharmony_ci unsigned short rec_len; 34258c2ecf20Sopenharmony_ci struct ocfs2_dir_entry *de; 34268c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 34278c2ecf20Sopenharmony_ci int status; 34288c2ecf20Sopenharmony_ci int blocksize = dir->i_sb->s_blocksize; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci status = ocfs2_read_dir_block(dir, 0, &bh, 0); 34318c2ecf20Sopenharmony_ci if (status) 34328c2ecf20Sopenharmony_ci goto bail; 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci rec_len = OCFS2_DIR_REC_LEN(namelen); 34358c2ecf20Sopenharmony_ci offset = 0; 34368c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) bh->b_data; 34378c2ecf20Sopenharmony_ci while (1) { 34388c2ecf20Sopenharmony_ci if ((char *)de >= sb->s_blocksize + bh->b_data) { 34398c2ecf20Sopenharmony_ci brelse(bh); 34408c2ecf20Sopenharmony_ci bh = NULL; 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci if (i_size_read(dir) <= offset) { 34438c2ecf20Sopenharmony_ci /* 34448c2ecf20Sopenharmony_ci * Caller will have to expand this 34458c2ecf20Sopenharmony_ci * directory. 34468c2ecf20Sopenharmony_ci */ 34478c2ecf20Sopenharmony_ci status = -ENOSPC; 34488c2ecf20Sopenharmony_ci goto bail; 34498c2ecf20Sopenharmony_ci } 34508c2ecf20Sopenharmony_ci status = ocfs2_read_dir_block(dir, 34518c2ecf20Sopenharmony_ci offset >> sb->s_blocksize_bits, 34528c2ecf20Sopenharmony_ci &bh, 0); 34538c2ecf20Sopenharmony_ci if (status) 34548c2ecf20Sopenharmony_ci goto bail; 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci /* move to next block */ 34578c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *) bh->b_data; 34588c2ecf20Sopenharmony_ci } 34598c2ecf20Sopenharmony_ci if (!ocfs2_check_dir_entry(dir, de, bh, bh->b_data, blocksize, 34608c2ecf20Sopenharmony_ci offset)) { 34618c2ecf20Sopenharmony_ci status = -ENOENT; 34628c2ecf20Sopenharmony_ci goto bail; 34638c2ecf20Sopenharmony_ci } 34648c2ecf20Sopenharmony_ci if (ocfs2_match(namelen, name, de)) { 34658c2ecf20Sopenharmony_ci status = -EEXIST; 34668c2ecf20Sopenharmony_ci goto bail; 34678c2ecf20Sopenharmony_ci } 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci if (ocfs2_skip_dir_trailer(dir, de, offset % blocksize, 34708c2ecf20Sopenharmony_ci blocksize)) 34718c2ecf20Sopenharmony_ci goto next; 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci if (ocfs2_dirent_would_fit(de, rec_len)) { 34748c2ecf20Sopenharmony_ci /* Ok, we found a spot. Return this bh and let 34758c2ecf20Sopenharmony_ci * the caller actually fill it in. */ 34768c2ecf20Sopenharmony_ci *ret_de_bh = bh; 34778c2ecf20Sopenharmony_ci get_bh(*ret_de_bh); 34788c2ecf20Sopenharmony_ci status = 0; 34798c2ecf20Sopenharmony_ci goto bail; 34808c2ecf20Sopenharmony_ci } 34818c2ecf20Sopenharmony_cinext: 34828c2ecf20Sopenharmony_ci offset += le16_to_cpu(de->rec_len); 34838c2ecf20Sopenharmony_ci de = (struct ocfs2_dir_entry *)((char *) de + le16_to_cpu(de->rec_len)); 34848c2ecf20Sopenharmony_ci } 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_cibail: 34878c2ecf20Sopenharmony_ci brelse(bh); 34888c2ecf20Sopenharmony_ci if (status) 34898c2ecf20Sopenharmony_ci mlog_errno(status); 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci return status; 34928c2ecf20Sopenharmony_ci} 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_cistatic int dx_leaf_sort_cmp(const void *a, const void *b) 34958c2ecf20Sopenharmony_ci{ 34968c2ecf20Sopenharmony_ci const struct ocfs2_dx_entry *entry1 = a; 34978c2ecf20Sopenharmony_ci const struct ocfs2_dx_entry *entry2 = b; 34988c2ecf20Sopenharmony_ci u32 major_hash1 = le32_to_cpu(entry1->dx_major_hash); 34998c2ecf20Sopenharmony_ci u32 major_hash2 = le32_to_cpu(entry2->dx_major_hash); 35008c2ecf20Sopenharmony_ci u32 minor_hash1 = le32_to_cpu(entry1->dx_minor_hash); 35018c2ecf20Sopenharmony_ci u32 minor_hash2 = le32_to_cpu(entry2->dx_minor_hash); 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci if (major_hash1 > major_hash2) 35048c2ecf20Sopenharmony_ci return 1; 35058c2ecf20Sopenharmony_ci if (major_hash1 < major_hash2) 35068c2ecf20Sopenharmony_ci return -1; 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci /* 35098c2ecf20Sopenharmony_ci * It is not strictly necessary to sort by minor 35108c2ecf20Sopenharmony_ci */ 35118c2ecf20Sopenharmony_ci if (minor_hash1 > minor_hash2) 35128c2ecf20Sopenharmony_ci return 1; 35138c2ecf20Sopenharmony_ci if (minor_hash1 < minor_hash2) 35148c2ecf20Sopenharmony_ci return -1; 35158c2ecf20Sopenharmony_ci return 0; 35168c2ecf20Sopenharmony_ci} 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_cistatic void dx_leaf_sort_swap(void *a, void *b, int size) 35198c2ecf20Sopenharmony_ci{ 35208c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *entry1 = a; 35218c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *entry2 = b; 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci BUG_ON(size != sizeof(*entry1)); 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci swap(*entry1, *entry2); 35268c2ecf20Sopenharmony_ci} 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_cistatic int ocfs2_dx_leaf_same_major(struct ocfs2_dx_leaf *dx_leaf) 35298c2ecf20Sopenharmony_ci{ 35308c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list; 35318c2ecf20Sopenharmony_ci int i, num = le16_to_cpu(dl_list->de_num_used); 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci for (i = 0; i < (num - 1); i++) { 35348c2ecf20Sopenharmony_ci if (le32_to_cpu(dl_list->de_entries[i].dx_major_hash) != 35358c2ecf20Sopenharmony_ci le32_to_cpu(dl_list->de_entries[i + 1].dx_major_hash)) 35368c2ecf20Sopenharmony_ci return 0; 35378c2ecf20Sopenharmony_ci } 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci return 1; 35408c2ecf20Sopenharmony_ci} 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci/* 35438c2ecf20Sopenharmony_ci * Find the optimal value to split this leaf on. This expects the leaf 35448c2ecf20Sopenharmony_ci * entries to be in sorted order. 35458c2ecf20Sopenharmony_ci * 35468c2ecf20Sopenharmony_ci * leaf_cpos is the cpos of the leaf we're splitting. insert_hash is 35478c2ecf20Sopenharmony_ci * the hash we want to insert. 35488c2ecf20Sopenharmony_ci * 35498c2ecf20Sopenharmony_ci * This function is only concerned with the major hash - that which 35508c2ecf20Sopenharmony_ci * determines which cluster an item belongs to. 35518c2ecf20Sopenharmony_ci */ 35528c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_find_leaf_split(struct ocfs2_dx_leaf *dx_leaf, 35538c2ecf20Sopenharmony_ci u32 leaf_cpos, u32 insert_hash, 35548c2ecf20Sopenharmony_ci u32 *split_hash) 35558c2ecf20Sopenharmony_ci{ 35568c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list; 35578c2ecf20Sopenharmony_ci int i, num_used = le16_to_cpu(dl_list->de_num_used); 35588c2ecf20Sopenharmony_ci int allsame; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci /* 35618c2ecf20Sopenharmony_ci * There's a couple rare, but nasty corner cases we have to 35628c2ecf20Sopenharmony_ci * check for here. All of them involve a leaf where all value 35638c2ecf20Sopenharmony_ci * have the same hash, which is what we look for first. 35648c2ecf20Sopenharmony_ci * 35658c2ecf20Sopenharmony_ci * Most of the time, all of the above is false, and we simply 35668c2ecf20Sopenharmony_ci * pick the median value for a split. 35678c2ecf20Sopenharmony_ci */ 35688c2ecf20Sopenharmony_ci allsame = ocfs2_dx_leaf_same_major(dx_leaf); 35698c2ecf20Sopenharmony_ci if (allsame) { 35708c2ecf20Sopenharmony_ci u32 val = le32_to_cpu(dl_list->de_entries[0].dx_major_hash); 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci if (val == insert_hash) { 35738c2ecf20Sopenharmony_ci /* 35748c2ecf20Sopenharmony_ci * No matter where we would choose to split, 35758c2ecf20Sopenharmony_ci * the new entry would want to occupy the same 35768c2ecf20Sopenharmony_ci * block as these. Since there's no space left 35778c2ecf20Sopenharmony_ci * in their existing block, we know there 35788c2ecf20Sopenharmony_ci * won't be space after the split. 35798c2ecf20Sopenharmony_ci */ 35808c2ecf20Sopenharmony_ci return -ENOSPC; 35818c2ecf20Sopenharmony_ci } 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci if (val == leaf_cpos) { 35848c2ecf20Sopenharmony_ci /* 35858c2ecf20Sopenharmony_ci * Because val is the same as leaf_cpos (which 35868c2ecf20Sopenharmony_ci * is the smallest value this leaf can have), 35878c2ecf20Sopenharmony_ci * yet is not equal to insert_hash, then we 35888c2ecf20Sopenharmony_ci * know that insert_hash *must* be larger than 35898c2ecf20Sopenharmony_ci * val (and leaf_cpos). At least cpos+1 in value. 35908c2ecf20Sopenharmony_ci * 35918c2ecf20Sopenharmony_ci * We also know then, that there cannot be an 35928c2ecf20Sopenharmony_ci * adjacent extent (otherwise we'd be looking 35938c2ecf20Sopenharmony_ci * at it). Choosing this value gives us a 35948c2ecf20Sopenharmony_ci * chance to get some contiguousness. 35958c2ecf20Sopenharmony_ci */ 35968c2ecf20Sopenharmony_ci *split_hash = leaf_cpos + 1; 35978c2ecf20Sopenharmony_ci return 0; 35988c2ecf20Sopenharmony_ci } 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci if (val > insert_hash) { 36018c2ecf20Sopenharmony_ci /* 36028c2ecf20Sopenharmony_ci * val can not be the same as insert hash, and 36038c2ecf20Sopenharmony_ci * also must be larger than leaf_cpos. Also, 36048c2ecf20Sopenharmony_ci * we know that there can't be a leaf between 36058c2ecf20Sopenharmony_ci * cpos and val, otherwise the entries with 36068c2ecf20Sopenharmony_ci * hash 'val' would be there. 36078c2ecf20Sopenharmony_ci */ 36088c2ecf20Sopenharmony_ci *split_hash = val; 36098c2ecf20Sopenharmony_ci return 0; 36108c2ecf20Sopenharmony_ci } 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci *split_hash = insert_hash; 36138c2ecf20Sopenharmony_ci return 0; 36148c2ecf20Sopenharmony_ci } 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci /* 36178c2ecf20Sopenharmony_ci * Since the records are sorted and the checks above 36188c2ecf20Sopenharmony_ci * guaranteed that not all records in this block are the same, 36198c2ecf20Sopenharmony_ci * we simple travel forward, from the median, and pick the 1st 36208c2ecf20Sopenharmony_ci * record whose value is larger than leaf_cpos. 36218c2ecf20Sopenharmony_ci */ 36228c2ecf20Sopenharmony_ci for (i = (num_used / 2); i < num_used; i++) 36238c2ecf20Sopenharmony_ci if (le32_to_cpu(dl_list->de_entries[i].dx_major_hash) > 36248c2ecf20Sopenharmony_ci leaf_cpos) 36258c2ecf20Sopenharmony_ci break; 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci BUG_ON(i == num_used); /* Should be impossible */ 36288c2ecf20Sopenharmony_ci *split_hash = le32_to_cpu(dl_list->de_entries[i].dx_major_hash); 36298c2ecf20Sopenharmony_ci return 0; 36308c2ecf20Sopenharmony_ci} 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci/* 36338c2ecf20Sopenharmony_ci * Transfer all entries in orig_dx_leaves whose major hash is equal to or 36348c2ecf20Sopenharmony_ci * larger than split_hash into new_dx_leaves. We use a temporary 36358c2ecf20Sopenharmony_ci * buffer (tmp_dx_leaf) to make the changes to the original leaf blocks. 36368c2ecf20Sopenharmony_ci * 36378c2ecf20Sopenharmony_ci * Since the block offset inside a leaf (cluster) is a constant mask 36388c2ecf20Sopenharmony_ci * of minor_hash, we can optimize - an item at block offset X within 36398c2ecf20Sopenharmony_ci * the original cluster, will be at offset X within the new cluster. 36408c2ecf20Sopenharmony_ci */ 36418c2ecf20Sopenharmony_cistatic void ocfs2_dx_dir_transfer_leaf(struct inode *dir, u32 split_hash, 36428c2ecf20Sopenharmony_ci handle_t *handle, 36438c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *tmp_dx_leaf, 36448c2ecf20Sopenharmony_ci struct buffer_head **orig_dx_leaves, 36458c2ecf20Sopenharmony_ci struct buffer_head **new_dx_leaves, 36468c2ecf20Sopenharmony_ci int num_dx_leaves) 36478c2ecf20Sopenharmony_ci{ 36488c2ecf20Sopenharmony_ci int i, j, num_used; 36498c2ecf20Sopenharmony_ci u32 major_hash; 36508c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *orig_dx_leaf, *new_dx_leaf; 36518c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *orig_list, *tmp_list; 36528c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *dx_entry; 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci tmp_list = &tmp_dx_leaf->dl_list; 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci for (i = 0; i < num_dx_leaves; i++) { 36578c2ecf20Sopenharmony_ci orig_dx_leaf = (struct ocfs2_dx_leaf *) orig_dx_leaves[i]->b_data; 36588c2ecf20Sopenharmony_ci orig_list = &orig_dx_leaf->dl_list; 36598c2ecf20Sopenharmony_ci new_dx_leaf = (struct ocfs2_dx_leaf *) new_dx_leaves[i]->b_data; 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci num_used = le16_to_cpu(orig_list->de_num_used); 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci memcpy(tmp_dx_leaf, orig_dx_leaf, dir->i_sb->s_blocksize); 36648c2ecf20Sopenharmony_ci tmp_list->de_num_used = cpu_to_le16(0); 36658c2ecf20Sopenharmony_ci memset(&tmp_list->de_entries, 0, sizeof(*dx_entry)*num_used); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci for (j = 0; j < num_used; j++) { 36688c2ecf20Sopenharmony_ci dx_entry = &orig_list->de_entries[j]; 36698c2ecf20Sopenharmony_ci major_hash = le32_to_cpu(dx_entry->dx_major_hash); 36708c2ecf20Sopenharmony_ci if (major_hash >= split_hash) 36718c2ecf20Sopenharmony_ci ocfs2_dx_dir_leaf_insert_tail(new_dx_leaf, 36728c2ecf20Sopenharmony_ci dx_entry); 36738c2ecf20Sopenharmony_ci else 36748c2ecf20Sopenharmony_ci ocfs2_dx_dir_leaf_insert_tail(tmp_dx_leaf, 36758c2ecf20Sopenharmony_ci dx_entry); 36768c2ecf20Sopenharmony_ci } 36778c2ecf20Sopenharmony_ci memcpy(orig_dx_leaf, tmp_dx_leaf, dir->i_sb->s_blocksize); 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, orig_dx_leaves[i]); 36808c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, new_dx_leaves[i]); 36818c2ecf20Sopenharmony_ci } 36828c2ecf20Sopenharmony_ci} 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_rebalance_credits(struct ocfs2_super *osb, 36858c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root) 36868c2ecf20Sopenharmony_ci{ 36878c2ecf20Sopenharmony_ci int credits = ocfs2_clusters_to_blocks(osb->sb, 3); 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci credits += ocfs2_calc_extend_credits(osb->sb, &dx_root->dr_list); 36908c2ecf20Sopenharmony_ci credits += ocfs2_quota_trans_credits(osb->sb); 36918c2ecf20Sopenharmony_ci return credits; 36928c2ecf20Sopenharmony_ci} 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci/* 36958c2ecf20Sopenharmony_ci * Find the median value in dx_leaf_bh and allocate a new leaf to move 36968c2ecf20Sopenharmony_ci * half our entries into. 36978c2ecf20Sopenharmony_ci */ 36988c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir, 36998c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh, 37008c2ecf20Sopenharmony_ci struct buffer_head *dx_leaf_bh, 37018c2ecf20Sopenharmony_ci struct ocfs2_dx_hinfo *hinfo, u32 leaf_cpos, 37028c2ecf20Sopenharmony_ci u64 leaf_blkno) 37038c2ecf20Sopenharmony_ci{ 37048c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data; 37058c2ecf20Sopenharmony_ci int credits, ret, i, num_used, did_quota = 0; 37068c2ecf20Sopenharmony_ci u32 cpos, split_hash, insert_hash = hinfo->major_hash; 37078c2ecf20Sopenharmony_ci u64 orig_leaves_start; 37088c2ecf20Sopenharmony_ci int num_dx_leaves; 37098c2ecf20Sopenharmony_ci struct buffer_head **orig_dx_leaves = NULL; 37108c2ecf20Sopenharmony_ci struct buffer_head **new_dx_leaves = NULL; 37118c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac = NULL, *meta_ac = NULL; 37128c2ecf20Sopenharmony_ci struct ocfs2_extent_tree et; 37138c2ecf20Sopenharmony_ci handle_t *handle = NULL; 37148c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 37158c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *tmp_dx_leaf = NULL; 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_rebalance((unsigned long long)OCFS2_I(dir)->ip_blkno, 37188c2ecf20Sopenharmony_ci (unsigned long long)leaf_blkno, 37198c2ecf20Sopenharmony_ci insert_hash); 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci ocfs2_init_dx_root_extent_tree(&et, INODE_CACHE(dir), dx_root_bh); 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 37248c2ecf20Sopenharmony_ci /* 37258c2ecf20Sopenharmony_ci * XXX: This is a rather large limit. We should use a more 37268c2ecf20Sopenharmony_ci * realistic value. 37278c2ecf20Sopenharmony_ci */ 37288c2ecf20Sopenharmony_ci if (le32_to_cpu(dx_root->dr_clusters) == UINT_MAX) 37298c2ecf20Sopenharmony_ci return -ENOSPC; 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci num_used = le16_to_cpu(dx_leaf->dl_list.de_num_used); 37328c2ecf20Sopenharmony_ci if (num_used < le16_to_cpu(dx_leaf->dl_list.de_count)) { 37338c2ecf20Sopenharmony_ci mlog(ML_ERROR, "DX Dir: %llu, Asked to rebalance empty leaf: " 37348c2ecf20Sopenharmony_ci "%llu, %d\n", (unsigned long long)OCFS2_I(dir)->ip_blkno, 37358c2ecf20Sopenharmony_ci (unsigned long long)leaf_blkno, num_used); 37368c2ecf20Sopenharmony_ci ret = -EIO; 37378c2ecf20Sopenharmony_ci goto out; 37388c2ecf20Sopenharmony_ci } 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci orig_dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, &num_dx_leaves); 37418c2ecf20Sopenharmony_ci if (!orig_dx_leaves) { 37428c2ecf20Sopenharmony_ci ret = -ENOMEM; 37438c2ecf20Sopenharmony_ci mlog_errno(ret); 37448c2ecf20Sopenharmony_ci goto out; 37458c2ecf20Sopenharmony_ci } 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci new_dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, NULL); 37488c2ecf20Sopenharmony_ci if (!new_dx_leaves) { 37498c2ecf20Sopenharmony_ci ret = -ENOMEM; 37508c2ecf20Sopenharmony_ci mlog_errno(ret); 37518c2ecf20Sopenharmony_ci goto out; 37528c2ecf20Sopenharmony_ci } 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci ret = ocfs2_lock_allocators(dir, &et, 1, 0, &data_ac, &meta_ac); 37558c2ecf20Sopenharmony_ci if (ret) { 37568c2ecf20Sopenharmony_ci if (ret != -ENOSPC) 37578c2ecf20Sopenharmony_ci mlog_errno(ret); 37588c2ecf20Sopenharmony_ci goto out; 37598c2ecf20Sopenharmony_ci } 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci credits = ocfs2_dx_dir_rebalance_credits(osb, dx_root); 37628c2ecf20Sopenharmony_ci handle = ocfs2_start_trans(osb, credits); 37638c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 37648c2ecf20Sopenharmony_ci ret = PTR_ERR(handle); 37658c2ecf20Sopenharmony_ci handle = NULL; 37668c2ecf20Sopenharmony_ci mlog_errno(ret); 37678c2ecf20Sopenharmony_ci goto out; 37688c2ecf20Sopenharmony_ci } 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci ret = dquot_alloc_space_nodirty(dir, 37718c2ecf20Sopenharmony_ci ocfs2_clusters_to_bytes(dir->i_sb, 1)); 37728c2ecf20Sopenharmony_ci if (ret) 37738c2ecf20Sopenharmony_ci goto out_commit; 37748c2ecf20Sopenharmony_ci did_quota = 1; 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), dx_leaf_bh, 37778c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 37788c2ecf20Sopenharmony_ci if (ret) { 37798c2ecf20Sopenharmony_ci mlog_errno(ret); 37808c2ecf20Sopenharmony_ci goto out_commit; 37818c2ecf20Sopenharmony_ci } 37828c2ecf20Sopenharmony_ci 37838c2ecf20Sopenharmony_ci /* 37848c2ecf20Sopenharmony_ci * This block is changing anyway, so we can sort it in place. 37858c2ecf20Sopenharmony_ci */ 37868c2ecf20Sopenharmony_ci sort(dx_leaf->dl_list.de_entries, num_used, 37878c2ecf20Sopenharmony_ci sizeof(struct ocfs2_dx_entry), dx_leaf_sort_cmp, 37888c2ecf20Sopenharmony_ci dx_leaf_sort_swap); 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_leaf_bh); 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_find_leaf_split(dx_leaf, leaf_cpos, insert_hash, 37938c2ecf20Sopenharmony_ci &split_hash); 37948c2ecf20Sopenharmony_ci if (ret) { 37958c2ecf20Sopenharmony_ci mlog_errno(ret); 37968c2ecf20Sopenharmony_ci goto out_commit; 37978c2ecf20Sopenharmony_ci } 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci trace_ocfs2_dx_dir_rebalance_split(leaf_cpos, split_hash, insert_hash); 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci /* 38028c2ecf20Sopenharmony_ci * We have to carefully order operations here. There are items 38038c2ecf20Sopenharmony_ci * which want to be in the new cluster before insert, but in 38048c2ecf20Sopenharmony_ci * order to put those items in the new cluster, we alter the 38058c2ecf20Sopenharmony_ci * old cluster. A failure to insert gets nasty. 38068c2ecf20Sopenharmony_ci * 38078c2ecf20Sopenharmony_ci * So, start by reserving writes to the old 38088c2ecf20Sopenharmony_ci * cluster. ocfs2_dx_dir_new_cluster will reserve writes on 38098c2ecf20Sopenharmony_ci * the new cluster for us, before inserting it. The insert 38108c2ecf20Sopenharmony_ci * won't happen if there's an error before that. Once the 38118c2ecf20Sopenharmony_ci * insert is done then, we can transfer from one leaf into the 38128c2ecf20Sopenharmony_ci * other without fear of hitting any error. 38138c2ecf20Sopenharmony_ci */ 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci /* 38168c2ecf20Sopenharmony_ci * The leaf transfer wants some scratch space so that we don't 38178c2ecf20Sopenharmony_ci * wind up doing a bunch of expensive memmove(). 38188c2ecf20Sopenharmony_ci */ 38198c2ecf20Sopenharmony_ci tmp_dx_leaf = kmalloc(osb->sb->s_blocksize, GFP_NOFS); 38208c2ecf20Sopenharmony_ci if (!tmp_dx_leaf) { 38218c2ecf20Sopenharmony_ci ret = -ENOMEM; 38228c2ecf20Sopenharmony_ci mlog_errno(ret); 38238c2ecf20Sopenharmony_ci goto out_commit; 38248c2ecf20Sopenharmony_ci } 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci orig_leaves_start = ocfs2_block_to_cluster_start(dir->i_sb, leaf_blkno); 38278c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_leaves(dir, orig_leaves_start, num_dx_leaves, 38288c2ecf20Sopenharmony_ci orig_dx_leaves); 38298c2ecf20Sopenharmony_ci if (ret) { 38308c2ecf20Sopenharmony_ci mlog_errno(ret); 38318c2ecf20Sopenharmony_ci goto out_commit; 38328c2ecf20Sopenharmony_ci } 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci cpos = split_hash; 38358c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle, 38368c2ecf20Sopenharmony_ci data_ac, meta_ac, new_dx_leaves, 38378c2ecf20Sopenharmony_ci num_dx_leaves); 38388c2ecf20Sopenharmony_ci if (ret) { 38398c2ecf20Sopenharmony_ci mlog_errno(ret); 38408c2ecf20Sopenharmony_ci goto out_commit; 38418c2ecf20Sopenharmony_ci } 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci for (i = 0; i < num_dx_leaves; i++) { 38448c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), 38458c2ecf20Sopenharmony_ci orig_dx_leaves[i], 38468c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 38478c2ecf20Sopenharmony_ci if (ret) { 38488c2ecf20Sopenharmony_ci mlog_errno(ret); 38498c2ecf20Sopenharmony_ci goto out_commit; 38508c2ecf20Sopenharmony_ci } 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), 38538c2ecf20Sopenharmony_ci new_dx_leaves[i], 38548c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 38558c2ecf20Sopenharmony_ci if (ret) { 38568c2ecf20Sopenharmony_ci mlog_errno(ret); 38578c2ecf20Sopenharmony_ci goto out_commit; 38588c2ecf20Sopenharmony_ci } 38598c2ecf20Sopenharmony_ci } 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf, 38628c2ecf20Sopenharmony_ci orig_dx_leaves, new_dx_leaves, num_dx_leaves); 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ciout_commit: 38658c2ecf20Sopenharmony_ci if (ret < 0 && did_quota) 38668c2ecf20Sopenharmony_ci dquot_free_space_nodirty(dir, 38678c2ecf20Sopenharmony_ci ocfs2_clusters_to_bytes(dir->i_sb, 1)); 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci ocfs2_update_inode_fsync_trans(handle, dir, 1); 38708c2ecf20Sopenharmony_ci ocfs2_commit_trans(osb, handle); 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ciout: 38738c2ecf20Sopenharmony_ci if (orig_dx_leaves || new_dx_leaves) { 38748c2ecf20Sopenharmony_ci for (i = 0; i < num_dx_leaves; i++) { 38758c2ecf20Sopenharmony_ci if (orig_dx_leaves) 38768c2ecf20Sopenharmony_ci brelse(orig_dx_leaves[i]); 38778c2ecf20Sopenharmony_ci if (new_dx_leaves) 38788c2ecf20Sopenharmony_ci brelse(new_dx_leaves[i]); 38798c2ecf20Sopenharmony_ci } 38808c2ecf20Sopenharmony_ci kfree(orig_dx_leaves); 38818c2ecf20Sopenharmony_ci kfree(new_dx_leaves); 38828c2ecf20Sopenharmony_ci } 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci if (meta_ac) 38858c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(meta_ac); 38868c2ecf20Sopenharmony_ci if (data_ac) 38878c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(data_ac); 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci kfree(tmp_dx_leaf); 38908c2ecf20Sopenharmony_ci return ret; 38918c2ecf20Sopenharmony_ci} 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_cistatic int ocfs2_find_dir_space_dx(struct ocfs2_super *osb, struct inode *dir, 38948c2ecf20Sopenharmony_ci struct buffer_head *di_bh, 38958c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh, 38968c2ecf20Sopenharmony_ci const char *name, int namelen, 38978c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 38988c2ecf20Sopenharmony_ci{ 38998c2ecf20Sopenharmony_ci int ret, rebalanced = 0; 39008c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 39018c2ecf20Sopenharmony_ci struct buffer_head *dx_leaf_bh = NULL; 39028c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *dx_leaf; 39038c2ecf20Sopenharmony_ci u64 blkno; 39048c2ecf20Sopenharmony_ci u32 leaf_cpos; 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 39078c2ecf20Sopenharmony_ci 39088c2ecf20Sopenharmony_cirestart_search: 39098c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_lookup(dir, &dx_root->dr_list, &lookup->dl_hinfo, 39108c2ecf20Sopenharmony_ci &leaf_cpos, &blkno); 39118c2ecf20Sopenharmony_ci if (ret) { 39128c2ecf20Sopenharmony_ci mlog_errno(ret); 39138c2ecf20Sopenharmony_ci goto out; 39148c2ecf20Sopenharmony_ci } 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_leaf(dir, blkno, &dx_leaf_bh); 39178c2ecf20Sopenharmony_ci if (ret) { 39188c2ecf20Sopenharmony_ci mlog_errno(ret); 39198c2ecf20Sopenharmony_ci goto out; 39208c2ecf20Sopenharmony_ci } 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data; 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci if (le16_to_cpu(dx_leaf->dl_list.de_num_used) >= 39258c2ecf20Sopenharmony_ci le16_to_cpu(dx_leaf->dl_list.de_count)) { 39268c2ecf20Sopenharmony_ci if (rebalanced) { 39278c2ecf20Sopenharmony_ci /* 39288c2ecf20Sopenharmony_ci * Rebalancing should have provided us with 39298c2ecf20Sopenharmony_ci * space in an appropriate leaf. 39308c2ecf20Sopenharmony_ci * 39318c2ecf20Sopenharmony_ci * XXX: Is this an abnormal condition then? 39328c2ecf20Sopenharmony_ci * Should we print a message here? 39338c2ecf20Sopenharmony_ci */ 39348c2ecf20Sopenharmony_ci ret = -ENOSPC; 39358c2ecf20Sopenharmony_ci goto out; 39368c2ecf20Sopenharmony_ci } 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_rebalance(osb, dir, dx_root_bh, dx_leaf_bh, 39398c2ecf20Sopenharmony_ci &lookup->dl_hinfo, leaf_cpos, 39408c2ecf20Sopenharmony_ci blkno); 39418c2ecf20Sopenharmony_ci if (ret) { 39428c2ecf20Sopenharmony_ci if (ret != -ENOSPC) 39438c2ecf20Sopenharmony_ci mlog_errno(ret); 39448c2ecf20Sopenharmony_ci goto out; 39458c2ecf20Sopenharmony_ci } 39468c2ecf20Sopenharmony_ci 39478c2ecf20Sopenharmony_ci /* 39488c2ecf20Sopenharmony_ci * Restart the lookup. The rebalance might have 39498c2ecf20Sopenharmony_ci * changed which block our item fits into. Mark our 39508c2ecf20Sopenharmony_ci * progress, so we only execute this once. 39518c2ecf20Sopenharmony_ci */ 39528c2ecf20Sopenharmony_ci brelse(dx_leaf_bh); 39538c2ecf20Sopenharmony_ci dx_leaf_bh = NULL; 39548c2ecf20Sopenharmony_ci rebalanced = 1; 39558c2ecf20Sopenharmony_ci goto restart_search; 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci lookup->dl_dx_leaf_bh = dx_leaf_bh; 39598c2ecf20Sopenharmony_ci dx_leaf_bh = NULL; 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ciout: 39628c2ecf20Sopenharmony_ci brelse(dx_leaf_bh); 39638c2ecf20Sopenharmony_ci return ret; 39648c2ecf20Sopenharmony_ci} 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_cistatic int ocfs2_search_dx_free_list(struct inode *dir, 39678c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh, 39688c2ecf20Sopenharmony_ci int namelen, 39698c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 39708c2ecf20Sopenharmony_ci{ 39718c2ecf20Sopenharmony_ci int ret = -ENOSPC; 39728c2ecf20Sopenharmony_ci struct buffer_head *leaf_bh = NULL, *prev_leaf_bh = NULL; 39738c2ecf20Sopenharmony_ci struct ocfs2_dir_block_trailer *db; 39748c2ecf20Sopenharmony_ci u64 next_block; 39758c2ecf20Sopenharmony_ci int rec_len = OCFS2_DIR_REC_LEN(namelen); 39768c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 39798c2ecf20Sopenharmony_ci next_block = le64_to_cpu(dx_root->dr_free_blk); 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci while (next_block) { 39828c2ecf20Sopenharmony_ci brelse(prev_leaf_bh); 39838c2ecf20Sopenharmony_ci prev_leaf_bh = leaf_bh; 39848c2ecf20Sopenharmony_ci leaf_bh = NULL; 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci ret = ocfs2_read_dir_block_direct(dir, next_block, &leaf_bh); 39878c2ecf20Sopenharmony_ci if (ret) { 39888c2ecf20Sopenharmony_ci mlog_errno(ret); 39898c2ecf20Sopenharmony_ci goto out; 39908c2ecf20Sopenharmony_ci } 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci db = ocfs2_trailer_from_bh(leaf_bh, dir->i_sb); 39938c2ecf20Sopenharmony_ci if (rec_len <= le16_to_cpu(db->db_free_rec_len)) { 39948c2ecf20Sopenharmony_ci lookup->dl_leaf_bh = leaf_bh; 39958c2ecf20Sopenharmony_ci lookup->dl_prev_leaf_bh = prev_leaf_bh; 39968c2ecf20Sopenharmony_ci leaf_bh = NULL; 39978c2ecf20Sopenharmony_ci prev_leaf_bh = NULL; 39988c2ecf20Sopenharmony_ci break; 39998c2ecf20Sopenharmony_ci } 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci next_block = le64_to_cpu(db->db_free_next); 40028c2ecf20Sopenharmony_ci } 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci if (!next_block) 40058c2ecf20Sopenharmony_ci ret = -ENOSPC; 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ciout: 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ci brelse(leaf_bh); 40108c2ecf20Sopenharmony_ci brelse(prev_leaf_bh); 40118c2ecf20Sopenharmony_ci return ret; 40128c2ecf20Sopenharmony_ci} 40138c2ecf20Sopenharmony_ci 40148c2ecf20Sopenharmony_cistatic int ocfs2_expand_inline_dx_root(struct inode *dir, 40158c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh) 40168c2ecf20Sopenharmony_ci{ 40178c2ecf20Sopenharmony_ci int ret, num_dx_leaves, i, j, did_quota = 0; 40188c2ecf20Sopenharmony_ci struct buffer_head **dx_leaves = NULL; 40198c2ecf20Sopenharmony_ci struct ocfs2_extent_tree et; 40208c2ecf20Sopenharmony_ci u64 insert_blkno; 40218c2ecf20Sopenharmony_ci struct ocfs2_alloc_context *data_ac = NULL; 40228c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 40238c2ecf20Sopenharmony_ci handle_t *handle = NULL; 40248c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 40258c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *entry_list; 40268c2ecf20Sopenharmony_ci struct ocfs2_dx_entry *dx_entry; 40278c2ecf20Sopenharmony_ci struct ocfs2_dx_leaf *target_leaf; 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ci ret = ocfs2_reserve_clusters(osb, 1, &data_ac); 40308c2ecf20Sopenharmony_ci if (ret) { 40318c2ecf20Sopenharmony_ci mlog_errno(ret); 40328c2ecf20Sopenharmony_ci goto out; 40338c2ecf20Sopenharmony_ci } 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, &num_dx_leaves); 40368c2ecf20Sopenharmony_ci if (!dx_leaves) { 40378c2ecf20Sopenharmony_ci ret = -ENOMEM; 40388c2ecf20Sopenharmony_ci mlog_errno(ret); 40398c2ecf20Sopenharmony_ci goto out; 40408c2ecf20Sopenharmony_ci } 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci handle = ocfs2_start_trans(osb, ocfs2_calc_dxi_expand_credits(osb->sb)); 40438c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 40448c2ecf20Sopenharmony_ci ret = PTR_ERR(handle); 40458c2ecf20Sopenharmony_ci mlog_errno(ret); 40468c2ecf20Sopenharmony_ci goto out; 40478c2ecf20Sopenharmony_ci } 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_ci ret = dquot_alloc_space_nodirty(dir, 40508c2ecf20Sopenharmony_ci ocfs2_clusters_to_bytes(osb->sb, 1)); 40518c2ecf20Sopenharmony_ci if (ret) 40528c2ecf20Sopenharmony_ci goto out_commit; 40538c2ecf20Sopenharmony_ci did_quota = 1; 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci /* 40568c2ecf20Sopenharmony_ci * We do this up front, before the allocation, so that a 40578c2ecf20Sopenharmony_ci * failure to add the dx_root_bh to the journal won't result 40588c2ecf20Sopenharmony_ci * us losing clusters. 40598c2ecf20Sopenharmony_ci */ 40608c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_dr(handle, INODE_CACHE(dir), dx_root_bh, 40618c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 40628c2ecf20Sopenharmony_ci if (ret) { 40638c2ecf20Sopenharmony_ci mlog_errno(ret); 40648c2ecf20Sopenharmony_ci goto out_commit; 40658c2ecf20Sopenharmony_ci } 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci ret = __ocfs2_dx_dir_new_cluster(dir, 0, handle, data_ac, dx_leaves, 40688c2ecf20Sopenharmony_ci num_dx_leaves, &insert_blkno); 40698c2ecf20Sopenharmony_ci if (ret) { 40708c2ecf20Sopenharmony_ci mlog_errno(ret); 40718c2ecf20Sopenharmony_ci goto out_commit; 40728c2ecf20Sopenharmony_ci } 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_ci /* 40758c2ecf20Sopenharmony_ci * Transfer the entries from our dx_root into the appropriate 40768c2ecf20Sopenharmony_ci * block 40778c2ecf20Sopenharmony_ci */ 40788c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; 40798c2ecf20Sopenharmony_ci entry_list = &dx_root->dr_entries; 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) { 40828c2ecf20Sopenharmony_ci dx_entry = &entry_list->de_entries[i]; 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci j = __ocfs2_dx_dir_hash_idx(osb, 40858c2ecf20Sopenharmony_ci le32_to_cpu(dx_entry->dx_minor_hash)); 40868c2ecf20Sopenharmony_ci target_leaf = (struct ocfs2_dx_leaf *)dx_leaves[j]->b_data; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci ocfs2_dx_dir_leaf_insert_tail(target_leaf, dx_entry); 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_ci /* Each leaf has been passed to the journal already 40918c2ecf20Sopenharmony_ci * via __ocfs2_dx_dir_new_cluster() */ 40928c2ecf20Sopenharmony_ci } 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci dx_root->dr_flags &= ~OCFS2_DX_FLAG_INLINE; 40958c2ecf20Sopenharmony_ci memset(&dx_root->dr_list, 0, osb->sb->s_blocksize - 40968c2ecf20Sopenharmony_ci offsetof(struct ocfs2_dx_root_block, dr_list)); 40978c2ecf20Sopenharmony_ci dx_root->dr_list.l_count = 40988c2ecf20Sopenharmony_ci cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb)); 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci /* This should never fail considering we start with an empty 41018c2ecf20Sopenharmony_ci * dx_root. */ 41028c2ecf20Sopenharmony_ci ocfs2_init_dx_root_extent_tree(&et, INODE_CACHE(dir), dx_root_bh); 41038c2ecf20Sopenharmony_ci ret = ocfs2_insert_extent(handle, &et, 0, insert_blkno, 1, 0, NULL); 41048c2ecf20Sopenharmony_ci if (ret) 41058c2ecf20Sopenharmony_ci mlog_errno(ret); 41068c2ecf20Sopenharmony_ci did_quota = 0; 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_ci ocfs2_update_inode_fsync_trans(handle, dir, 1); 41098c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, dx_root_bh); 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ciout_commit: 41128c2ecf20Sopenharmony_ci if (ret < 0 && did_quota) 41138c2ecf20Sopenharmony_ci dquot_free_space_nodirty(dir, 41148c2ecf20Sopenharmony_ci ocfs2_clusters_to_bytes(dir->i_sb, 1)); 41158c2ecf20Sopenharmony_ci 41168c2ecf20Sopenharmony_ci ocfs2_commit_trans(osb, handle); 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ciout: 41198c2ecf20Sopenharmony_ci if (data_ac) 41208c2ecf20Sopenharmony_ci ocfs2_free_alloc_context(data_ac); 41218c2ecf20Sopenharmony_ci 41228c2ecf20Sopenharmony_ci if (dx_leaves) { 41238c2ecf20Sopenharmony_ci for (i = 0; i < num_dx_leaves; i++) 41248c2ecf20Sopenharmony_ci brelse(dx_leaves[i]); 41258c2ecf20Sopenharmony_ci kfree(dx_leaves); 41268c2ecf20Sopenharmony_ci } 41278c2ecf20Sopenharmony_ci return ret; 41288c2ecf20Sopenharmony_ci} 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_cistatic int ocfs2_inline_dx_has_space(struct buffer_head *dx_root_bh) 41318c2ecf20Sopenharmony_ci{ 41328c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 41338c2ecf20Sopenharmony_ci struct ocfs2_dx_entry_list *entry_list; 41348c2ecf20Sopenharmony_ci 41358c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; 41368c2ecf20Sopenharmony_ci entry_list = &dx_root->dr_entries; 41378c2ecf20Sopenharmony_ci 41388c2ecf20Sopenharmony_ci if (le16_to_cpu(entry_list->de_num_used) >= 41398c2ecf20Sopenharmony_ci le16_to_cpu(entry_list->de_count)) 41408c2ecf20Sopenharmony_ci return -ENOSPC; 41418c2ecf20Sopenharmony_ci 41428c2ecf20Sopenharmony_ci return 0; 41438c2ecf20Sopenharmony_ci} 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_cistatic int ocfs2_prepare_dx_dir_for_insert(struct inode *dir, 41468c2ecf20Sopenharmony_ci struct buffer_head *di_bh, 41478c2ecf20Sopenharmony_ci const char *name, 41488c2ecf20Sopenharmony_ci int namelen, 41498c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 41508c2ecf20Sopenharmony_ci{ 41518c2ecf20Sopenharmony_ci int ret, free_dx_root = 1; 41528c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 41538c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 41548c2ecf20Sopenharmony_ci struct buffer_head *leaf_bh = NULL; 41558c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 41568c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_root(dir, di, &dx_root_bh); 41598c2ecf20Sopenharmony_ci if (ret) { 41608c2ecf20Sopenharmony_ci mlog_errno(ret); 41618c2ecf20Sopenharmony_ci goto out; 41628c2ecf20Sopenharmony_ci } 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 41658c2ecf20Sopenharmony_ci if (le32_to_cpu(dx_root->dr_num_entries) == OCFS2_DX_ENTRIES_MAX) { 41668c2ecf20Sopenharmony_ci ret = -ENOSPC; 41678c2ecf20Sopenharmony_ci mlog_errno(ret); 41688c2ecf20Sopenharmony_ci goto out; 41698c2ecf20Sopenharmony_ci } 41708c2ecf20Sopenharmony_ci 41718c2ecf20Sopenharmony_ci if (ocfs2_dx_root_inline(dx_root)) { 41728c2ecf20Sopenharmony_ci ret = ocfs2_inline_dx_has_space(dx_root_bh); 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_ci if (ret == 0) 41758c2ecf20Sopenharmony_ci goto search_el; 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci /* 41788c2ecf20Sopenharmony_ci * We ran out of room in the root block. Expand it to 41798c2ecf20Sopenharmony_ci * an extent, then allow ocfs2_find_dir_space_dx to do 41808c2ecf20Sopenharmony_ci * the rest. 41818c2ecf20Sopenharmony_ci */ 41828c2ecf20Sopenharmony_ci ret = ocfs2_expand_inline_dx_root(dir, dx_root_bh); 41838c2ecf20Sopenharmony_ci if (ret) { 41848c2ecf20Sopenharmony_ci mlog_errno(ret); 41858c2ecf20Sopenharmony_ci goto out; 41868c2ecf20Sopenharmony_ci } 41878c2ecf20Sopenharmony_ci } 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci /* 41908c2ecf20Sopenharmony_ci * Insert preparation for an indexed directory is split into two 41918c2ecf20Sopenharmony_ci * steps. The call to find_dir_space_dx reserves room in the index for 41928c2ecf20Sopenharmony_ci * an additional item. If we run out of space there, it's a real error 41938c2ecf20Sopenharmony_ci * we can't continue on. 41948c2ecf20Sopenharmony_ci */ 41958c2ecf20Sopenharmony_ci ret = ocfs2_find_dir_space_dx(osb, dir, di_bh, dx_root_bh, name, 41968c2ecf20Sopenharmony_ci namelen, lookup); 41978c2ecf20Sopenharmony_ci if (ret) { 41988c2ecf20Sopenharmony_ci mlog_errno(ret); 41998c2ecf20Sopenharmony_ci goto out; 42008c2ecf20Sopenharmony_ci } 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_cisearch_el: 42038c2ecf20Sopenharmony_ci /* 42048c2ecf20Sopenharmony_ci * Next, we need to find space in the unindexed tree. This call 42058c2ecf20Sopenharmony_ci * searches using the free space linked list. If the unindexed tree 42068c2ecf20Sopenharmony_ci * lacks sufficient space, we'll expand it below. The expansion code 42078c2ecf20Sopenharmony_ci * is smart enough to add any new blocks to the free space list. 42088c2ecf20Sopenharmony_ci */ 42098c2ecf20Sopenharmony_ci ret = ocfs2_search_dx_free_list(dir, dx_root_bh, namelen, lookup); 42108c2ecf20Sopenharmony_ci if (ret && ret != -ENOSPC) { 42118c2ecf20Sopenharmony_ci mlog_errno(ret); 42128c2ecf20Sopenharmony_ci goto out; 42138c2ecf20Sopenharmony_ci } 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci /* Do this up here - ocfs2_extend_dir might need the dx_root */ 42168c2ecf20Sopenharmony_ci lookup->dl_dx_root_bh = dx_root_bh; 42178c2ecf20Sopenharmony_ci free_dx_root = 0; 42188c2ecf20Sopenharmony_ci 42198c2ecf20Sopenharmony_ci if (ret == -ENOSPC) { 42208c2ecf20Sopenharmony_ci ret = ocfs2_extend_dir(osb, dir, di_bh, 1, lookup, &leaf_bh); 42218c2ecf20Sopenharmony_ci 42228c2ecf20Sopenharmony_ci if (ret) { 42238c2ecf20Sopenharmony_ci mlog_errno(ret); 42248c2ecf20Sopenharmony_ci goto out; 42258c2ecf20Sopenharmony_ci } 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci /* 42288c2ecf20Sopenharmony_ci * We make the assumption here that new leaf blocks are added 42298c2ecf20Sopenharmony_ci * to the front of our free list. 42308c2ecf20Sopenharmony_ci */ 42318c2ecf20Sopenharmony_ci lookup->dl_prev_leaf_bh = NULL; 42328c2ecf20Sopenharmony_ci lookup->dl_leaf_bh = leaf_bh; 42338c2ecf20Sopenharmony_ci } 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ciout: 42368c2ecf20Sopenharmony_ci if (free_dx_root) 42378c2ecf20Sopenharmony_ci brelse(dx_root_bh); 42388c2ecf20Sopenharmony_ci return ret; 42398c2ecf20Sopenharmony_ci} 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci/* 42428c2ecf20Sopenharmony_ci * Get a directory ready for insert. Any directory allocation required 42438c2ecf20Sopenharmony_ci * happens here. Success returns zero, and enough context in the dir 42448c2ecf20Sopenharmony_ci * lookup result that ocfs2_add_entry() will be able complete the task 42458c2ecf20Sopenharmony_ci * with minimal performance impact. 42468c2ecf20Sopenharmony_ci */ 42478c2ecf20Sopenharmony_ciint ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, 42488c2ecf20Sopenharmony_ci struct inode *dir, 42498c2ecf20Sopenharmony_ci struct buffer_head *parent_fe_bh, 42508c2ecf20Sopenharmony_ci const char *name, 42518c2ecf20Sopenharmony_ci int namelen, 42528c2ecf20Sopenharmony_ci struct ocfs2_dir_lookup_result *lookup) 42538c2ecf20Sopenharmony_ci{ 42548c2ecf20Sopenharmony_ci int ret; 42558c2ecf20Sopenharmony_ci unsigned int blocks_wanted = 1; 42568c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci trace_ocfs2_prepare_dir_for_insert( 42598c2ecf20Sopenharmony_ci (unsigned long long)OCFS2_I(dir)->ip_blkno, namelen); 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_ci if (!namelen) { 42628c2ecf20Sopenharmony_ci ret = -EINVAL; 42638c2ecf20Sopenharmony_ci mlog_errno(ret); 42648c2ecf20Sopenharmony_ci goto out; 42658c2ecf20Sopenharmony_ci } 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci /* 42688c2ecf20Sopenharmony_ci * Do this up front to reduce confusion. 42698c2ecf20Sopenharmony_ci * 42708c2ecf20Sopenharmony_ci * The directory might start inline, then be turned into an 42718c2ecf20Sopenharmony_ci * indexed one, in which case we'd need to hash deep inside 42728c2ecf20Sopenharmony_ci * ocfs2_find_dir_space_id(). Since 42738c2ecf20Sopenharmony_ci * ocfs2_prepare_dx_dir_for_insert() also needs this hash 42748c2ecf20Sopenharmony_ci * done, there seems no point in spreading out the calls. We 42758c2ecf20Sopenharmony_ci * can optimize away the case where the file system doesn't 42768c2ecf20Sopenharmony_ci * support indexing. 42778c2ecf20Sopenharmony_ci */ 42788c2ecf20Sopenharmony_ci if (ocfs2_supports_indexed_dirs(osb)) 42798c2ecf20Sopenharmony_ci ocfs2_dx_dir_name_hash(dir, name, namelen, &lookup->dl_hinfo); 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci if (ocfs2_dir_indexed(dir)) { 42828c2ecf20Sopenharmony_ci ret = ocfs2_prepare_dx_dir_for_insert(dir, parent_fe_bh, 42838c2ecf20Sopenharmony_ci name, namelen, lookup); 42848c2ecf20Sopenharmony_ci if (ret) 42858c2ecf20Sopenharmony_ci mlog_errno(ret); 42868c2ecf20Sopenharmony_ci goto out; 42878c2ecf20Sopenharmony_ci } 42888c2ecf20Sopenharmony_ci 42898c2ecf20Sopenharmony_ci if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { 42908c2ecf20Sopenharmony_ci ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name, 42918c2ecf20Sopenharmony_ci namelen, &bh, &blocks_wanted); 42928c2ecf20Sopenharmony_ci } else 42938c2ecf20Sopenharmony_ci ret = ocfs2_find_dir_space_el(dir, name, namelen, &bh); 42948c2ecf20Sopenharmony_ci 42958c2ecf20Sopenharmony_ci if (ret && ret != -ENOSPC) { 42968c2ecf20Sopenharmony_ci mlog_errno(ret); 42978c2ecf20Sopenharmony_ci goto out; 42988c2ecf20Sopenharmony_ci } 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci if (ret == -ENOSPC) { 43018c2ecf20Sopenharmony_ci /* 43028c2ecf20Sopenharmony_ci * We have to expand the directory to add this name. 43038c2ecf20Sopenharmony_ci */ 43048c2ecf20Sopenharmony_ci BUG_ON(bh); 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted, 43078c2ecf20Sopenharmony_ci lookup, &bh); 43088c2ecf20Sopenharmony_ci if (ret) { 43098c2ecf20Sopenharmony_ci if (ret != -ENOSPC) 43108c2ecf20Sopenharmony_ci mlog_errno(ret); 43118c2ecf20Sopenharmony_ci goto out; 43128c2ecf20Sopenharmony_ci } 43138c2ecf20Sopenharmony_ci 43148c2ecf20Sopenharmony_ci BUG_ON(!bh); 43158c2ecf20Sopenharmony_ci } 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci lookup->dl_leaf_bh = bh; 43188c2ecf20Sopenharmony_ci bh = NULL; 43198c2ecf20Sopenharmony_ciout: 43208c2ecf20Sopenharmony_ci brelse(bh); 43218c2ecf20Sopenharmony_ci return ret; 43228c2ecf20Sopenharmony_ci} 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_cistatic int ocfs2_dx_dir_remove_index(struct inode *dir, 43258c2ecf20Sopenharmony_ci struct buffer_head *di_bh, 43268c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh) 43278c2ecf20Sopenharmony_ci{ 43288c2ecf20Sopenharmony_ci int ret; 43298c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 43308c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 43318c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 43328c2ecf20Sopenharmony_ci struct inode *dx_alloc_inode = NULL; 43338c2ecf20Sopenharmony_ci struct buffer_head *dx_alloc_bh = NULL; 43348c2ecf20Sopenharmony_ci handle_t *handle; 43358c2ecf20Sopenharmony_ci u64 blk; 43368c2ecf20Sopenharmony_ci u16 bit; 43378c2ecf20Sopenharmony_ci u64 bg_blkno; 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_ci dx_alloc_inode = ocfs2_get_system_file_inode(osb, 43428c2ecf20Sopenharmony_ci EXTENT_ALLOC_SYSTEM_INODE, 43438c2ecf20Sopenharmony_ci le16_to_cpu(dx_root->dr_suballoc_slot)); 43448c2ecf20Sopenharmony_ci if (!dx_alloc_inode) { 43458c2ecf20Sopenharmony_ci ret = -ENOMEM; 43468c2ecf20Sopenharmony_ci mlog_errno(ret); 43478c2ecf20Sopenharmony_ci goto out; 43488c2ecf20Sopenharmony_ci } 43498c2ecf20Sopenharmony_ci inode_lock(dx_alloc_inode); 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci ret = ocfs2_inode_lock(dx_alloc_inode, &dx_alloc_bh, 1); 43528c2ecf20Sopenharmony_ci if (ret) { 43538c2ecf20Sopenharmony_ci mlog_errno(ret); 43548c2ecf20Sopenharmony_ci goto out_mutex; 43558c2ecf20Sopenharmony_ci } 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci handle = ocfs2_start_trans(osb, OCFS2_DX_ROOT_REMOVE_CREDITS); 43588c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 43598c2ecf20Sopenharmony_ci ret = PTR_ERR(handle); 43608c2ecf20Sopenharmony_ci mlog_errno(ret); 43618c2ecf20Sopenharmony_ci goto out_unlock; 43628c2ecf20Sopenharmony_ci } 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci ret = ocfs2_journal_access_di(handle, INODE_CACHE(dir), di_bh, 43658c2ecf20Sopenharmony_ci OCFS2_JOURNAL_ACCESS_WRITE); 43668c2ecf20Sopenharmony_ci if (ret) { 43678c2ecf20Sopenharmony_ci mlog_errno(ret); 43688c2ecf20Sopenharmony_ci goto out_commit; 43698c2ecf20Sopenharmony_ci } 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ci spin_lock(&OCFS2_I(dir)->ip_lock); 43728c2ecf20Sopenharmony_ci OCFS2_I(dir)->ip_dyn_features &= ~OCFS2_INDEXED_DIR_FL; 43738c2ecf20Sopenharmony_ci di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features); 43748c2ecf20Sopenharmony_ci spin_unlock(&OCFS2_I(dir)->ip_lock); 43758c2ecf20Sopenharmony_ci di->i_dx_root = cpu_to_le64(0ULL); 43768c2ecf20Sopenharmony_ci ocfs2_update_inode_fsync_trans(handle, dir, 1); 43778c2ecf20Sopenharmony_ci 43788c2ecf20Sopenharmony_ci ocfs2_journal_dirty(handle, di_bh); 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci blk = le64_to_cpu(dx_root->dr_blkno); 43818c2ecf20Sopenharmony_ci bit = le16_to_cpu(dx_root->dr_suballoc_bit); 43828c2ecf20Sopenharmony_ci if (dx_root->dr_suballoc_loc) 43838c2ecf20Sopenharmony_ci bg_blkno = le64_to_cpu(dx_root->dr_suballoc_loc); 43848c2ecf20Sopenharmony_ci else 43858c2ecf20Sopenharmony_ci bg_blkno = ocfs2_which_suballoc_group(blk, bit); 43868c2ecf20Sopenharmony_ci ret = ocfs2_free_suballoc_bits(handle, dx_alloc_inode, dx_alloc_bh, 43878c2ecf20Sopenharmony_ci bit, bg_blkno, 1); 43888c2ecf20Sopenharmony_ci if (ret) 43898c2ecf20Sopenharmony_ci mlog_errno(ret); 43908c2ecf20Sopenharmony_ci 43918c2ecf20Sopenharmony_ciout_commit: 43928c2ecf20Sopenharmony_ci ocfs2_commit_trans(osb, handle); 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ciout_unlock: 43958c2ecf20Sopenharmony_ci ocfs2_inode_unlock(dx_alloc_inode, 1); 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_ciout_mutex: 43988c2ecf20Sopenharmony_ci inode_unlock(dx_alloc_inode); 43998c2ecf20Sopenharmony_ci brelse(dx_alloc_bh); 44008c2ecf20Sopenharmony_ciout: 44018c2ecf20Sopenharmony_ci iput(dx_alloc_inode); 44028c2ecf20Sopenharmony_ci return ret; 44038c2ecf20Sopenharmony_ci} 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ciint ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh) 44068c2ecf20Sopenharmony_ci{ 44078c2ecf20Sopenharmony_ci int ret; 44088c2ecf20Sopenharmony_ci unsigned int clen; 44098c2ecf20Sopenharmony_ci u32 major_hash = UINT_MAX, p_cpos, cpos; 44108c2ecf20Sopenharmony_ci u64 blkno; 44118c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 44128c2ecf20Sopenharmony_ci struct buffer_head *dx_root_bh = NULL; 44138c2ecf20Sopenharmony_ci struct ocfs2_dx_root_block *dx_root; 44148c2ecf20Sopenharmony_ci struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; 44158c2ecf20Sopenharmony_ci struct ocfs2_cached_dealloc_ctxt dealloc; 44168c2ecf20Sopenharmony_ci struct ocfs2_extent_tree et; 44178c2ecf20Sopenharmony_ci 44188c2ecf20Sopenharmony_ci ocfs2_init_dealloc_ctxt(&dealloc); 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ci if (!ocfs2_dir_indexed(dir)) 44218c2ecf20Sopenharmony_ci return 0; 44228c2ecf20Sopenharmony_ci 44238c2ecf20Sopenharmony_ci ret = ocfs2_read_dx_root(dir, di, &dx_root_bh); 44248c2ecf20Sopenharmony_ci if (ret) { 44258c2ecf20Sopenharmony_ci mlog_errno(ret); 44268c2ecf20Sopenharmony_ci goto out; 44278c2ecf20Sopenharmony_ci } 44288c2ecf20Sopenharmony_ci dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; 44298c2ecf20Sopenharmony_ci 44308c2ecf20Sopenharmony_ci if (ocfs2_dx_root_inline(dx_root)) 44318c2ecf20Sopenharmony_ci goto remove_index; 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ci ocfs2_init_dx_root_extent_tree(&et, INODE_CACHE(dir), dx_root_bh); 44348c2ecf20Sopenharmony_ci 44358c2ecf20Sopenharmony_ci /* XXX: What if dr_clusters is too large? */ 44368c2ecf20Sopenharmony_ci while (le32_to_cpu(dx_root->dr_clusters)) { 44378c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_lookup_rec(dir, &dx_root->dr_list, 44388c2ecf20Sopenharmony_ci major_hash, &cpos, &blkno, &clen); 44398c2ecf20Sopenharmony_ci if (ret) { 44408c2ecf20Sopenharmony_ci mlog_errno(ret); 44418c2ecf20Sopenharmony_ci goto out; 44428c2ecf20Sopenharmony_ci } 44438c2ecf20Sopenharmony_ci 44448c2ecf20Sopenharmony_ci p_cpos = ocfs2_blocks_to_clusters(dir->i_sb, blkno); 44458c2ecf20Sopenharmony_ci 44468c2ecf20Sopenharmony_ci ret = ocfs2_remove_btree_range(dir, &et, cpos, p_cpos, clen, 0, 44478c2ecf20Sopenharmony_ci &dealloc, 0, false); 44488c2ecf20Sopenharmony_ci if (ret) { 44498c2ecf20Sopenharmony_ci mlog_errno(ret); 44508c2ecf20Sopenharmony_ci goto out; 44518c2ecf20Sopenharmony_ci } 44528c2ecf20Sopenharmony_ci 44538c2ecf20Sopenharmony_ci if (cpos == 0) 44548c2ecf20Sopenharmony_ci break; 44558c2ecf20Sopenharmony_ci 44568c2ecf20Sopenharmony_ci major_hash = cpos - 1; 44578c2ecf20Sopenharmony_ci } 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_ciremove_index: 44608c2ecf20Sopenharmony_ci ret = ocfs2_dx_dir_remove_index(dir, di_bh, dx_root_bh); 44618c2ecf20Sopenharmony_ci if (ret) { 44628c2ecf20Sopenharmony_ci mlog_errno(ret); 44638c2ecf20Sopenharmony_ci goto out; 44648c2ecf20Sopenharmony_ci } 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci ocfs2_remove_from_cache(INODE_CACHE(dir), dx_root_bh); 44678c2ecf20Sopenharmony_ciout: 44688c2ecf20Sopenharmony_ci ocfs2_schedule_truncate_log_flush(osb, 1); 44698c2ecf20Sopenharmony_ci ocfs2_run_deallocs(osb, &dealloc); 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci brelse(dx_root_bh); 44728c2ecf20Sopenharmony_ci return ret; 44738c2ecf20Sopenharmony_ci} 4474