18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2013 Jie Liu. 48c2ecf20Sopenharmony_ci * All Rights Reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "xfs.h" 78c2ecf20Sopenharmony_ci#include "xfs_fs.h" 88c2ecf20Sopenharmony_ci#include "xfs_shared.h" 98c2ecf20Sopenharmony_ci#include "xfs_format.h" 108c2ecf20Sopenharmony_ci#include "xfs_log_format.h" 118c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h" 128c2ecf20Sopenharmony_ci#include "xfs_mount.h" 138c2ecf20Sopenharmony_ci#include "xfs_da_format.h" 148c2ecf20Sopenharmony_ci#include "xfs_trans_space.h" 158c2ecf20Sopenharmony_ci#include "xfs_da_btree.h" 168c2ecf20Sopenharmony_ci#include "xfs_bmap_btree.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* 198c2ecf20Sopenharmony_ci * Calculate the maximum length in bytes that would be required for a local 208c2ecf20Sopenharmony_ci * attribute value as large attributes out of line are not logged. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ciSTATIC int 238c2ecf20Sopenharmony_cixfs_log_calc_max_attrsetm_res( 248c2ecf20Sopenharmony_ci struct xfs_mount *mp) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci int size; 278c2ecf20Sopenharmony_ci int nblks; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - 308c2ecf20Sopenharmony_ci MAXNAMELEN - 1; 318c2ecf20Sopenharmony_ci nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); 328c2ecf20Sopenharmony_ci nblks += XFS_B_TO_FSB(mp, size); 338c2ecf20Sopenharmony_ci nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return M_RES(mp)->tr_attrsetm.tr_logres + 368c2ecf20Sopenharmony_ci M_RES(mp)->tr_attrsetrt.tr_logres * nblks; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Iterate over the log space reservation table to figure out and return 418c2ecf20Sopenharmony_ci * the maximum one in terms of the pre-calculated values which were done 428c2ecf20Sopenharmony_ci * at mount time. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_civoid 458c2ecf20Sopenharmony_cixfs_log_get_max_trans_res( 468c2ecf20Sopenharmony_ci struct xfs_mount *mp, 478c2ecf20Sopenharmony_ci struct xfs_trans_res *max_resp) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct xfs_trans_res *resp; 508c2ecf20Sopenharmony_ci struct xfs_trans_res *end_resp; 518c2ecf20Sopenharmony_ci int log_space = 0; 528c2ecf20Sopenharmony_ci int attr_space; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci attr_space = xfs_log_calc_max_attrsetm_res(mp); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci resp = (struct xfs_trans_res *)M_RES(mp); 578c2ecf20Sopenharmony_ci end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); 588c2ecf20Sopenharmony_ci for (; resp < end_resp; resp++) { 598c2ecf20Sopenharmony_ci int tmp = resp->tr_logcount > 1 ? 608c2ecf20Sopenharmony_ci resp->tr_logres * resp->tr_logcount : 618c2ecf20Sopenharmony_ci resp->tr_logres; 628c2ecf20Sopenharmony_ci if (log_space < tmp) { 638c2ecf20Sopenharmony_ci log_space = tmp; 648c2ecf20Sopenharmony_ci *max_resp = *resp; /* struct copy */ 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (attr_space > log_space) { 698c2ecf20Sopenharmony_ci *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ 708c2ecf20Sopenharmony_ci max_resp->tr_logres = attr_space; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci * Calculate the minimum valid log size for the given superblock configuration. 768c2ecf20Sopenharmony_ci * Used to calculate the minimum log size at mkfs time, and to determine if 778c2ecf20Sopenharmony_ci * the log is large enough or not at mount time. Returns the minimum size in 788c2ecf20Sopenharmony_ci * filesystem block size units. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ciint 818c2ecf20Sopenharmony_cixfs_log_calc_minimum_size( 828c2ecf20Sopenharmony_ci struct xfs_mount *mp) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct xfs_trans_res tres = {0}; 858c2ecf20Sopenharmony_ci int max_logres; 868c2ecf20Sopenharmony_ci int min_logblks = 0; 878c2ecf20Sopenharmony_ci int lsunit = 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci xfs_log_get_max_trans_res(mp, &tres); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); 928c2ecf20Sopenharmony_ci if (tres.tr_logcount > 1) 938c2ecf20Sopenharmony_ci max_logres *= tres.tr_logcount; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) 968c2ecf20Sopenharmony_ci lsunit = BTOBB(mp->m_sb.sb_logsunit); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * Two factors should be taken into account for calculating the minimum 1008c2ecf20Sopenharmony_ci * log space. 1018c2ecf20Sopenharmony_ci * 1) The fundamental limitation is that no single transaction can be 1028c2ecf20Sopenharmony_ci * larger than half size of the log. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR 1058c2ecf20Sopenharmony_ci * define, which is set to 3. That means we can definitely fit 1068c2ecf20Sopenharmony_ci * maximally sized 2 transactions in the log. We'll use this same 1078c2ecf20Sopenharmony_ci * value here. 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * 2) If the lsunit option is specified, a transaction requires 2 LSU 1108c2ecf20Sopenharmony_ci * for the reservation because there are two log writes that can 1118c2ecf20Sopenharmony_ci * require padding - the transaction data and the commit record which 1128c2ecf20Sopenharmony_ci * are written separately and both can require padding to the LSU. 1138c2ecf20Sopenharmony_ci * Consider that we can have an active CIL reservation holding 2*LSU, 1148c2ecf20Sopenharmony_ci * but the CIL is not over a push threshold, in this case, if we 1158c2ecf20Sopenharmony_ci * don't have enough log space for at one new transaction, which 1168c2ecf20Sopenharmony_ci * includes another 2*LSU in the reservation, we will run into dead 1178c2ecf20Sopenharmony_ci * loop situation in log space grant procedure. i.e. 1188c2ecf20Sopenharmony_ci * xlog_grant_head_wait(). 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * Hence the log size needs to be able to contain two maximally sized 1218c2ecf20Sopenharmony_ci * and padded transactions, which is (2 * (2 * LSU + maxlres)). 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * Also, the log size should be a multiple of the log stripe unit, round 1248c2ecf20Sopenharmony_ci * it up to lsunit boundary if lsunit is specified. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci if (lsunit) { 1278c2ecf20Sopenharmony_ci min_logblks = roundup_64(BTOBB(max_logres), lsunit) + 1288c2ecf20Sopenharmony_ci 2 * lsunit; 1298c2ecf20Sopenharmony_ci } else 1308c2ecf20Sopenharmony_ci min_logblks = BTOBB(max_logres) + 2 * BBSIZE; 1318c2ecf20Sopenharmony_ci min_logblks *= XFS_MIN_LOG_FACTOR; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return XFS_BB_TO_FSB(mp, min_logblks); 1348c2ecf20Sopenharmony_ci} 135