1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2013 Jie Liu. 4 * All Rights Reserved. 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_log_format.h" 11 #include "xfs_trans_resv.h" 12 #include "xfs_mount.h" 13 #include "xfs_da_format.h" 14 #include "xfs_trans_space.h" 15 #include "xfs_inode.h" 16 #include "xfs_da_btree.h" 17 #include "xfs_attr_leaf.h" 18 #include "xfs_bmap_btree.h" 19 20 /* 21 * Calculate the maximum length in bytes that would be required for a local 22 * attribute value as large attributes out of line are not logged. 23 */ 24 STATIC int 25 xfs_log_calc_max_attrsetm_res( 26 struct xfs_mount *mp) 27 { 28 int size; 29 int nblks; 30 31 size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - 32 MAXNAMELEN - 1; 33 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); 34 nblks += XFS_B_TO_FSB(mp, size); 35 nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); 36 37 return M_RES(mp)->tr_attrsetm.tr_logres + 38 M_RES(mp)->tr_attrsetrt.tr_logres * nblks; 39 } 40 41 /* 42 * Iterate over the log space reservation table to figure out and return 43 * the maximum one in terms of the pre-calculated values which were done 44 * at mount time. 45 */ 46 void 47 xfs_log_get_max_trans_res( 48 struct xfs_mount *mp, 49 struct xfs_trans_res *max_resp) 50 { 51 struct xfs_trans_res *resp; 52 struct xfs_trans_res *end_resp; 53 int log_space = 0; 54 int attr_space; 55 56 attr_space = xfs_log_calc_max_attrsetm_res(mp); 57 58 resp = (struct xfs_trans_res *)M_RES(mp); 59 end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); 60 for (; resp < end_resp; resp++) { 61 int tmp = resp->tr_logcount > 1 ? 62 resp->tr_logres * resp->tr_logcount : 63 resp->tr_logres; 64 if (log_space < tmp) { 65 log_space = tmp; 66 *max_resp = *resp; /* struct copy */ 67 } 68 } 69 70 if (attr_space > log_space) { 71 *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ 72 max_resp->tr_logres = attr_space; 73 } 74 } 75 76 /* 77 * Calculate the minimum valid log size for the given superblock configuration. 78 * Used to calculate the minimum log size at mkfs time, and to determine if 79 * the log is large enough or not at mount time. Returns the minimum size in 80 * filesystem block size units. 81 */ 82 int 83 xfs_log_calc_minimum_size( 84 struct xfs_mount *mp) 85 { 86 struct xfs_trans_res tres = {0}; 87 int max_logres; 88 int min_logblks = 0; 89 int lsunit = 0; 90 91 xfs_log_get_max_trans_res(mp, &tres); 92 93 max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); 94 if (tres.tr_logcount > 1) 95 max_logres *= tres.tr_logcount; 96 97 if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) 98 lsunit = BTOBB(mp->m_sb.sb_logsunit); 99 100 /* 101 * Two factors should be taken into account for calculating the minimum 102 * log space. 103 * 1) The fundamental limitation is that no single transaction can be 104 * larger than half size of the log. 105 * 106 * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR 107 * define, which is set to 3. That means we can definitely fit 108 * maximally sized 2 transactions in the log. We'll use this same 109 * value here. 110 * 111 * 2) If the lsunit option is specified, a transaction requires 2 LSU 112 * for the reservation because there are two log writes that can 113 * require padding - the transaction data and the commit record which 114 * are written separately and both can require padding to the LSU. 115 * Consider that we can have an active CIL reservation holding 2*LSU, 116 * but the CIL is not over a push threshold, in this case, if we 117 * don't have enough log space for at one new transaction, which 118 * includes another 2*LSU in the reservation, we will run into dead 119 * loop situation in log space grant procedure. i.e. 120 * xlog_grant_head_wait(). 121 * 122 * Hence the log size needs to be able to contain two maximally sized 123 * and padded transactions, which is (2 * (2 * LSU + maxlres)). 124 * 125 * Also, the log size should be a multiple of the log stripe unit, round 126 * it up to lsunit boundary if lsunit is specified. 127 */ 128 if (lsunit) { 129 min_logblks = roundup_64(BTOBB(max_logres), lsunit) + 130 2 * lsunit; 131 } else 132 min_logblks = BTOBB(max_logres) + 2 * BBSIZE; 133 min_logblks *= XFS_MIN_LOG_FACTOR; 134 135 return XFS_BB_TO_FSB(mp, min_logblks); 136 } 137