| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 1 | /* -*- mode: c; c-basic-offset: 8; -*- | 
|  | 2 | * vim: noexpandtab sw=8 ts=8 sts=0: | 
|  | 3 | * | 
|  | 4 | * resize.c | 
|  | 5 | * | 
|  | 6 | * volume resize. | 
|  | 7 | * Inspired by ext3/resize.c. | 
|  | 8 | * | 
|  | 9 | * Copyright (C) 2007 Oracle.  All rights reserved. | 
|  | 10 | * | 
|  | 11 | * This program is free software; you can redistribute it and/or | 
|  | 12 | * modify it under the terms of the GNU General Public | 
|  | 13 | * License as published by the Free Software Foundation; either | 
|  | 14 | * version 2 of the License, or (at your option) any later version. | 
|  | 15 | * | 
|  | 16 | * This program is distributed in the hope that it will be useful, | 
|  | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 19 | * General Public License for more details. | 
|  | 20 | * | 
|  | 21 | * You should have received a copy of the GNU General Public | 
|  | 22 | * License along with this program; if not, write to the | 
|  | 23 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 
|  | 24 | * Boston, MA 021110-1307, USA. | 
|  | 25 | */ | 
|  | 26 |  | 
|  | 27 | #include <linux/fs.h> | 
|  | 28 | #include <linux/types.h> | 
|  | 29 |  | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 30 | #include <cluster/masklog.h> | 
|  | 31 |  | 
|  | 32 | #include "ocfs2.h" | 
|  | 33 |  | 
|  | 34 | #include "alloc.h" | 
|  | 35 | #include "dlmglue.h" | 
|  | 36 | #include "inode.h" | 
|  | 37 | #include "journal.h" | 
|  | 38 | #include "super.h" | 
|  | 39 | #include "sysfile.h" | 
|  | 40 | #include "uptodate.h" | 
| Tao Ma | a543870 | 2011-02-22 08:24:01 +0800 | [diff] [blame] | 41 | #include "ocfs2_trace.h" | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 42 |  | 
|  | 43 | #include "buffer_head_io.h" | 
|  | 44 | #include "suballoc.h" | 
|  | 45 | #include "resize.h" | 
|  | 46 |  | 
|  | 47 | /* | 
|  | 48 | * Check whether there are new backup superblocks exist | 
|  | 49 | * in the last group. If there are some, mark them or clear | 
|  | 50 | * them in the bitmap. | 
|  | 51 | * | 
|  | 52 | * Return how many backups we find in the last group. | 
|  | 53 | */ | 
|  | 54 | static u16 ocfs2_calc_new_backup_super(struct inode *inode, | 
|  | 55 | struct ocfs2_group_desc *gd, | 
|  | 56 | int new_clusters, | 
|  | 57 | u32 first_new_cluster, | 
|  | 58 | u16 cl_cpg, | 
|  | 59 | int set) | 
|  | 60 | { | 
|  | 61 | int i; | 
|  | 62 | u16 backups = 0; | 
|  | 63 | u32 cluster; | 
|  | 64 | u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno); | 
|  | 65 |  | 
|  | 66 | for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) { | 
|  | 67 | blkno = ocfs2_backup_super_blkno(inode->i_sb, i); | 
|  | 68 | cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno); | 
|  | 69 |  | 
|  | 70 | gd_blkno = ocfs2_which_cluster_group(inode, cluster); | 
|  | 71 | if (gd_blkno < lgd_blkno) | 
|  | 72 | continue; | 
|  | 73 | else if (gd_blkno > lgd_blkno) | 
|  | 74 | break; | 
|  | 75 |  | 
|  | 76 | if (set) | 
|  | 77 | ocfs2_set_bit(cluster % cl_cpg, | 
|  | 78 | (unsigned long *)gd->bg_bitmap); | 
|  | 79 | else | 
|  | 80 | ocfs2_clear_bit(cluster % cl_cpg, | 
|  | 81 | (unsigned long *)gd->bg_bitmap); | 
|  | 82 | backups++; | 
|  | 83 | } | 
|  | 84 |  | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 85 | return backups; | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | static int ocfs2_update_last_group_and_inode(handle_t *handle, | 
|  | 89 | struct inode *bm_inode, | 
|  | 90 | struct buffer_head *bm_bh, | 
|  | 91 | struct buffer_head *group_bh, | 
|  | 92 | u32 first_new_cluster, | 
|  | 93 | int new_clusters) | 
|  | 94 | { | 
|  | 95 | int ret = 0; | 
|  | 96 | struct ocfs2_super *osb = OCFS2_SB(bm_inode->i_sb); | 
|  | 97 | struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bm_bh->b_data; | 
|  | 98 | struct ocfs2_chain_list *cl = &fe->id2.i_chain; | 
|  | 99 | struct ocfs2_chain_rec *cr; | 
|  | 100 | struct ocfs2_group_desc *group; | 
|  | 101 | u16 chain, num_bits, backups = 0; | 
|  | 102 | u16 cl_bpc = le16_to_cpu(cl->cl_bpc); | 
|  | 103 | u16 cl_cpg = le16_to_cpu(cl->cl_cpg); | 
|  | 104 |  | 
| Tao Ma | a543870 | 2011-02-22 08:24:01 +0800 | [diff] [blame] | 105 | trace_ocfs2_update_last_group_and_inode(new_clusters, | 
|  | 106 | first_new_cluster); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 107 |  | 
| Joel Becker | 0cf2f76 | 2009-02-12 16:41:25 -0800 | [diff] [blame] | 108 | ret = ocfs2_journal_access_gd(handle, INODE_CACHE(bm_inode), | 
|  | 109 | group_bh, OCFS2_JOURNAL_ACCESS_WRITE); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 110 | if (ret < 0) { | 
|  | 111 | mlog_errno(ret); | 
|  | 112 | goto out; | 
|  | 113 | } | 
|  | 114 |  | 
|  | 115 | group = (struct ocfs2_group_desc *)group_bh->b_data; | 
|  | 116 |  | 
|  | 117 | /* update the group first. */ | 
|  | 118 | num_bits = new_clusters * cl_bpc; | 
|  | 119 | le16_add_cpu(&group->bg_bits, num_bits); | 
|  | 120 | le16_add_cpu(&group->bg_free_bits_count, num_bits); | 
|  | 121 |  | 
|  | 122 | /* | 
|  | 123 | * check whether there are some new backup superblocks exist in | 
|  | 124 | * this group and update the group bitmap accordingly. | 
|  | 125 | */ | 
|  | 126 | if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, | 
|  | 127 | OCFS2_FEATURE_COMPAT_BACKUP_SB)) { | 
|  | 128 | backups = ocfs2_calc_new_backup_super(bm_inode, | 
|  | 129 | group, | 
|  | 130 | new_clusters, | 
|  | 131 | first_new_cluster, | 
|  | 132 | cl_cpg, 1); | 
|  | 133 | le16_add_cpu(&group->bg_free_bits_count, -1 * backups); | 
|  | 134 | } | 
|  | 135 |  | 
| Joel Becker | ec20cec | 2010-03-19 14:13:52 -0700 | [diff] [blame] | 136 | ocfs2_journal_dirty(handle, group_bh); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 137 |  | 
|  | 138 | /* update the inode accordingly. */ | 
| Joel Becker | 0cf2f76 | 2009-02-12 16:41:25 -0800 | [diff] [blame] | 139 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(bm_inode), bm_bh, | 
| Joel Becker | 13723d0 | 2008-10-17 19:25:01 -0700 | [diff] [blame] | 140 | OCFS2_JOURNAL_ACCESS_WRITE); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 141 | if (ret < 0) { | 
|  | 142 | mlog_errno(ret); | 
|  | 143 | goto out_rollback; | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | chain = le16_to_cpu(group->bg_chain); | 
|  | 147 | cr = (&cl->cl_recs[chain]); | 
|  | 148 | le32_add_cpu(&cr->c_total, num_bits); | 
|  | 149 | le32_add_cpu(&cr->c_free, num_bits); | 
|  | 150 | le32_add_cpu(&fe->id1.bitmap1.i_total, num_bits); | 
|  | 151 | le32_add_cpu(&fe->i_clusters, new_clusters); | 
|  | 152 |  | 
|  | 153 | if (backups) { | 
|  | 154 | le32_add_cpu(&cr->c_free, -1 * backups); | 
|  | 155 | le32_add_cpu(&fe->id1.bitmap1.i_used, backups); | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | spin_lock(&OCFS2_I(bm_inode)->ip_lock); | 
|  | 159 | OCFS2_I(bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters); | 
|  | 160 | le64_add_cpu(&fe->i_size, new_clusters << osb->s_clustersize_bits); | 
|  | 161 | spin_unlock(&OCFS2_I(bm_inode)->ip_lock); | 
|  | 162 | i_size_write(bm_inode, le64_to_cpu(fe->i_size)); | 
|  | 163 |  | 
|  | 164 | ocfs2_journal_dirty(handle, bm_bh); | 
|  | 165 |  | 
|  | 166 | out_rollback: | 
|  | 167 | if (ret < 0) { | 
|  | 168 | ocfs2_calc_new_backup_super(bm_inode, | 
|  | 169 | group, | 
|  | 170 | new_clusters, | 
|  | 171 | first_new_cluster, | 
|  | 172 | cl_cpg, 0); | 
|  | 173 | le16_add_cpu(&group->bg_free_bits_count, backups); | 
|  | 174 | le16_add_cpu(&group->bg_bits, -1 * num_bits); | 
|  | 175 | le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits); | 
|  | 176 | } | 
|  | 177 | out: | 
| Tao Ma | c1e8d35 | 2011-03-07 16:43:21 +0800 | [diff] [blame] | 178 | if (ret) | 
|  | 179 | mlog_errno(ret); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 180 | return ret; | 
|  | 181 | } | 
|  | 182 |  | 
|  | 183 | static int update_backups(struct inode * inode, u32 clusters, char *data) | 
|  | 184 | { | 
|  | 185 | int i, ret = 0; | 
|  | 186 | u32 cluster; | 
|  | 187 | u64 blkno; | 
|  | 188 | struct buffer_head *backup = NULL; | 
|  | 189 | struct ocfs2_dinode *backup_di = NULL; | 
|  | 190 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 
|  | 191 |  | 
|  | 192 | /* calculate the real backups we need to update. */ | 
|  | 193 | for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) { | 
|  | 194 | blkno = ocfs2_backup_super_blkno(inode->i_sb, i); | 
|  | 195 | cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno); | 
|  | 196 | if (cluster > clusters) | 
|  | 197 | break; | 
|  | 198 |  | 
| Joel Becker | da1e909 | 2008-10-09 17:20:29 -0700 | [diff] [blame] | 199 | ret = ocfs2_read_blocks_sync(osb, blkno, 1, &backup); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 200 | if (ret < 0) { | 
|  | 201 | mlog_errno(ret); | 
|  | 202 | break; | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | memcpy(backup->b_data, data, inode->i_sb->s_blocksize); | 
|  | 206 |  | 
|  | 207 | backup_di = (struct ocfs2_dinode *)backup->b_data; | 
|  | 208 | backup_di->i_blkno = cpu_to_le64(blkno); | 
|  | 209 |  | 
|  | 210 | ret = ocfs2_write_super_or_backup(osb, backup); | 
|  | 211 | brelse(backup); | 
|  | 212 | backup = NULL; | 
|  | 213 | if (ret < 0) { | 
|  | 214 | mlog_errno(ret); | 
|  | 215 | break; | 
|  | 216 | } | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | return ret; | 
|  | 220 | } | 
|  | 221 |  | 
|  | 222 | static void ocfs2_update_super_and_backups(struct inode *inode, | 
|  | 223 | int new_clusters) | 
|  | 224 | { | 
|  | 225 | int ret; | 
|  | 226 | u32 clusters = 0; | 
|  | 227 | struct buffer_head *super_bh = NULL; | 
|  | 228 | struct ocfs2_dinode *super_di = NULL; | 
|  | 229 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 
|  | 230 |  | 
|  | 231 | /* | 
|  | 232 | * update the superblock last. | 
|  | 233 | * It doesn't matter if the write failed. | 
|  | 234 | */ | 
| Joel Becker | da1e909 | 2008-10-09 17:20:29 -0700 | [diff] [blame] | 235 | ret = ocfs2_read_blocks_sync(osb, OCFS2_SUPER_BLOCK_BLKNO, 1, | 
|  | 236 | &super_bh); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 237 | if (ret < 0) { | 
|  | 238 | mlog_errno(ret); | 
|  | 239 | goto out; | 
|  | 240 | } | 
|  | 241 |  | 
|  | 242 | super_di = (struct ocfs2_dinode *)super_bh->b_data; | 
|  | 243 | le32_add_cpu(&super_di->i_clusters, new_clusters); | 
|  | 244 | clusters = le32_to_cpu(super_di->i_clusters); | 
|  | 245 |  | 
|  | 246 | ret = ocfs2_write_super_or_backup(osb, super_bh); | 
|  | 247 | if (ret < 0) { | 
|  | 248 | mlog_errno(ret); | 
|  | 249 | goto out; | 
|  | 250 | } | 
|  | 251 |  | 
|  | 252 | if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_COMPAT_BACKUP_SB)) | 
|  | 253 | ret = update_backups(inode, clusters, super_bh->b_data); | 
|  | 254 |  | 
|  | 255 | out: | 
| Mark Fasheh | 2fe5c1d | 2008-01-23 18:35:31 -0800 | [diff] [blame] | 256 | brelse(super_bh); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 257 | if (ret) | 
|  | 258 | printk(KERN_WARNING "ocfs2: Failed to update super blocks on %s" | 
|  | 259 | " during fs resize. This condition is not fatal," | 
|  | 260 | " but fsck.ocfs2 should be run to fix it\n", | 
|  | 261 | osb->dev_str); | 
|  | 262 | return; | 
|  | 263 | } | 
|  | 264 |  | 
|  | 265 | /* | 
|  | 266 | * Extend the filesystem to the new number of clusters specified.  This entry | 
|  | 267 | * point is only used to extend the current filesystem to the end of the last | 
|  | 268 | * existing group. | 
|  | 269 | */ | 
|  | 270 | int ocfs2_group_extend(struct inode * inode, int new_clusters) | 
|  | 271 | { | 
|  | 272 | int ret; | 
|  | 273 | handle_t *handle; | 
|  | 274 | struct buffer_head *main_bm_bh = NULL; | 
|  | 275 | struct buffer_head *group_bh = NULL; | 
|  | 276 | struct inode *main_bm_inode = NULL; | 
|  | 277 | struct ocfs2_dinode *fe = NULL; | 
|  | 278 | struct ocfs2_group_desc *group = NULL; | 
|  | 279 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 
|  | 280 | u16 cl_bpc; | 
|  | 281 | u32 first_new_cluster; | 
|  | 282 | u64 lgd_blkno; | 
|  | 283 |  | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 284 | if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) | 
|  | 285 | return -EROFS; | 
|  | 286 |  | 
|  | 287 | if (new_clusters < 0) | 
|  | 288 | return -EINVAL; | 
|  | 289 | else if (new_clusters == 0) | 
|  | 290 | return 0; | 
|  | 291 |  | 
|  | 292 | main_bm_inode = ocfs2_get_system_file_inode(osb, | 
|  | 293 | GLOBAL_BITMAP_SYSTEM_INODE, | 
|  | 294 | OCFS2_INVALID_SLOT); | 
|  | 295 | if (!main_bm_inode) { | 
|  | 296 | ret = -EINVAL; | 
|  | 297 | mlog_errno(ret); | 
|  | 298 | goto out; | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | mutex_lock(&main_bm_inode->i_mutex); | 
|  | 302 |  | 
|  | 303 | ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); | 
|  | 304 | if (ret < 0) { | 
|  | 305 | mlog_errno(ret); | 
|  | 306 | goto out_mutex; | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | fe = (struct ocfs2_dinode *)main_bm_bh->b_data; | 
|  | 310 |  | 
| Joel Becker | 10995aa | 2008-11-13 14:49:12 -0800 | [diff] [blame] | 311 | /* main_bm_bh is validated by inode read inside ocfs2_inode_lock(), | 
|  | 312 | * so any corruption is a code bug. */ | 
|  | 313 | BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); | 
|  | 314 |  | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 315 | if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != | 
| Tao Ma | 8571882 | 2010-04-13 14:38:06 +0800 | [diff] [blame] | 316 | ocfs2_group_bitmap_size(osb->sb, 0, | 
|  | 317 | osb->s_feature_incompat) * 8) { | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 318 | mlog(ML_ERROR, "The disk is too old and small. " | 
|  | 319 | "Force to do offline resize."); | 
|  | 320 | ret = -EINVAL; | 
|  | 321 | goto out_unlock; | 
|  | 322 | } | 
|  | 323 |  | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 324 | first_new_cluster = le32_to_cpu(fe->i_clusters); | 
|  | 325 | lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, | 
|  | 326 | first_new_cluster - 1); | 
|  | 327 |  | 
| Joel Becker | 68f64d4 | 2008-11-13 14:49:14 -0800 | [diff] [blame] | 328 | ret = ocfs2_read_group_descriptor(main_bm_inode, fe, lgd_blkno, | 
|  | 329 | &group_bh); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 330 | if (ret < 0) { | 
|  | 331 | mlog_errno(ret); | 
|  | 332 | goto out_unlock; | 
|  | 333 | } | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 334 | group = (struct ocfs2_group_desc *)group_bh->b_data; | 
|  | 335 |  | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 336 | cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); | 
|  | 337 | if (le16_to_cpu(group->bg_bits) / cl_bpc + new_clusters > | 
|  | 338 | le16_to_cpu(fe->id2.i_chain.cl_cpg)) { | 
|  | 339 | ret = -EINVAL; | 
|  | 340 | goto out_unlock; | 
|  | 341 | } | 
|  | 342 |  | 
| Tao Ma | a543870 | 2011-02-22 08:24:01 +0800 | [diff] [blame] | 343 |  | 
|  | 344 | trace_ocfs2_group_extend( | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 345 | (unsigned long long)le64_to_cpu(group->bg_blkno), new_clusters); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 346 |  | 
|  | 347 | handle = ocfs2_start_trans(osb, OCFS2_GROUP_EXTEND_CREDITS); | 
|  | 348 | if (IS_ERR(handle)) { | 
|  | 349 | mlog_errno(PTR_ERR(handle)); | 
|  | 350 | ret = -EINVAL; | 
|  | 351 | goto out_unlock; | 
|  | 352 | } | 
|  | 353 |  | 
|  | 354 | /* update the last group descriptor and inode. */ | 
|  | 355 | ret = ocfs2_update_last_group_and_inode(handle, main_bm_inode, | 
|  | 356 | main_bm_bh, group_bh, | 
|  | 357 | first_new_cluster, | 
|  | 358 | new_clusters); | 
|  | 359 | if (ret) { | 
|  | 360 | mlog_errno(ret); | 
|  | 361 | goto out_commit; | 
|  | 362 | } | 
|  | 363 |  | 
|  | 364 | ocfs2_update_super_and_backups(main_bm_inode, new_clusters); | 
|  | 365 |  | 
|  | 366 | out_commit: | 
|  | 367 | ocfs2_commit_trans(osb, handle); | 
|  | 368 | out_unlock: | 
| Mark Fasheh | 2fe5c1d | 2008-01-23 18:35:31 -0800 | [diff] [blame] | 369 | brelse(group_bh); | 
|  | 370 | brelse(main_bm_bh); | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 371 |  | 
|  | 372 | ocfs2_inode_unlock(main_bm_inode, 1); | 
|  | 373 |  | 
|  | 374 | out_mutex: | 
|  | 375 | mutex_unlock(&main_bm_inode->i_mutex); | 
|  | 376 | iput(main_bm_inode); | 
|  | 377 |  | 
|  | 378 | out: | 
| Tao Ma | d659072 | 2007-12-18 15:47:03 +0800 | [diff] [blame] | 379 | return ret; | 
|  | 380 | } | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 381 |  | 
|  | 382 | static int ocfs2_check_new_group(struct inode *inode, | 
|  | 383 | struct ocfs2_dinode *di, | 
|  | 384 | struct ocfs2_new_group_input *input, | 
|  | 385 | struct buffer_head *group_bh) | 
|  | 386 | { | 
|  | 387 | int ret; | 
| Joel Becker | 57e3e79 | 2008-11-13 14:49:13 -0800 | [diff] [blame] | 388 | struct ocfs2_group_desc *gd = | 
|  | 389 | (struct ocfs2_group_desc *)group_bh->b_data; | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 390 | u16 cl_bpc = le16_to_cpu(di->id2.i_chain.cl_bpc); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 391 |  | 
| Joel Becker | 970e493 | 2008-11-13 14:49:19 -0800 | [diff] [blame] | 392 | ret = ocfs2_check_group_descriptor(inode->i_sb, di, group_bh); | 
| Joel Becker | 57e3e79 | 2008-11-13 14:49:13 -0800 | [diff] [blame] | 393 | if (ret) | 
|  | 394 | goto out; | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 395 |  | 
| Joel Becker | 57e3e79 | 2008-11-13 14:49:13 -0800 | [diff] [blame] | 396 | ret = -EINVAL; | 
|  | 397 | if (le16_to_cpu(gd->bg_chain) != input->chain) | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 398 | mlog(ML_ERROR, "Group descriptor # %llu has bad chain %u " | 
|  | 399 | "while input has %u set.\n", | 
|  | 400 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | 
|  | 401 | le16_to_cpu(gd->bg_chain), input->chain); | 
|  | 402 | else if (le16_to_cpu(gd->bg_bits) != input->clusters * cl_bpc) | 
|  | 403 | mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but " | 
|  | 404 | "input has %u clusters set\n", | 
|  | 405 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | 
|  | 406 | le16_to_cpu(gd->bg_bits), input->clusters); | 
|  | 407 | else if (le16_to_cpu(gd->bg_free_bits_count) != input->frees * cl_bpc) | 
|  | 408 | mlog(ML_ERROR, "Group descriptor # %llu has free bit count %u " | 
|  | 409 | "but it should have %u set\n", | 
|  | 410 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | 
|  | 411 | le16_to_cpu(gd->bg_bits), | 
|  | 412 | input->frees * cl_bpc); | 
|  | 413 | else | 
|  | 414 | ret = 0; | 
|  | 415 |  | 
| Joel Becker | 57e3e79 | 2008-11-13 14:49:13 -0800 | [diff] [blame] | 416 | out: | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 417 | return ret; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | static int ocfs2_verify_group_and_input(struct inode *inode, | 
|  | 421 | struct ocfs2_dinode *di, | 
|  | 422 | struct ocfs2_new_group_input *input, | 
|  | 423 | struct buffer_head *group_bh) | 
|  | 424 | { | 
|  | 425 | u16 cl_count = le16_to_cpu(di->id2.i_chain.cl_count); | 
|  | 426 | u16 cl_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg); | 
|  | 427 | u16 next_free = le16_to_cpu(di->id2.i_chain.cl_next_free_rec); | 
|  | 428 | u32 cluster = ocfs2_blocks_to_clusters(inode->i_sb, input->group); | 
|  | 429 | u32 total_clusters = le32_to_cpu(di->i_clusters); | 
|  | 430 | int ret = -EINVAL; | 
|  | 431 |  | 
|  | 432 | if (cluster < total_clusters) | 
|  | 433 | mlog(ML_ERROR, "add a group which is in the current volume.\n"); | 
|  | 434 | else if (input->chain >= cl_count) | 
|  | 435 | mlog(ML_ERROR, "input chain exceeds the limit.\n"); | 
|  | 436 | else if (next_free != cl_count && next_free != input->chain) | 
|  | 437 | mlog(ML_ERROR, | 
|  | 438 | "the add group should be in chain %u\n", next_free); | 
|  | 439 | else if (total_clusters + input->clusters < total_clusters) | 
|  | 440 | mlog(ML_ERROR, "add group's clusters overflow.\n"); | 
|  | 441 | else if (input->clusters > cl_cpg) | 
|  | 442 | mlog(ML_ERROR, "the cluster exceeds the maximum of a group\n"); | 
|  | 443 | else if (input->frees > input->clusters) | 
|  | 444 | mlog(ML_ERROR, "the free cluster exceeds the total clusters\n"); | 
|  | 445 | else if (total_clusters % cl_cpg != 0) | 
|  | 446 | mlog(ML_ERROR, | 
|  | 447 | "the last group isn't full. Use group extend first.\n"); | 
|  | 448 | else if (input->group != ocfs2_which_cluster_group(inode, cluster)) | 
|  | 449 | mlog(ML_ERROR, "group blkno is invalid\n"); | 
|  | 450 | else if ((ret = ocfs2_check_new_group(inode, di, input, group_bh))) | 
|  | 451 | mlog(ML_ERROR, "group descriptor check failed.\n"); | 
|  | 452 | else | 
|  | 453 | ret = 0; | 
|  | 454 |  | 
|  | 455 | return ret; | 
|  | 456 | } | 
|  | 457 |  | 
|  | 458 | /* Add a new group descriptor to global_bitmap. */ | 
|  | 459 | int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) | 
|  | 460 | { | 
|  | 461 | int ret; | 
|  | 462 | handle_t *handle; | 
|  | 463 | struct buffer_head *main_bm_bh = NULL; | 
|  | 464 | struct inode *main_bm_inode = NULL; | 
|  | 465 | struct ocfs2_dinode *fe = NULL; | 
|  | 466 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 
|  | 467 | struct buffer_head *group_bh = NULL; | 
|  | 468 | struct ocfs2_group_desc *group = NULL; | 
|  | 469 | struct ocfs2_chain_list *cl; | 
|  | 470 | struct ocfs2_chain_rec *cr; | 
|  | 471 | u16 cl_bpc; | 
|  | 472 |  | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 473 | if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) | 
|  | 474 | return -EROFS; | 
|  | 475 |  | 
|  | 476 | main_bm_inode = ocfs2_get_system_file_inode(osb, | 
|  | 477 | GLOBAL_BITMAP_SYSTEM_INODE, | 
|  | 478 | OCFS2_INVALID_SLOT); | 
|  | 479 | if (!main_bm_inode) { | 
|  | 480 | ret = -EINVAL; | 
|  | 481 | mlog_errno(ret); | 
|  | 482 | goto out; | 
|  | 483 | } | 
|  | 484 |  | 
|  | 485 | mutex_lock(&main_bm_inode->i_mutex); | 
|  | 486 |  | 
|  | 487 | ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); | 
|  | 488 | if (ret < 0) { | 
|  | 489 | mlog_errno(ret); | 
|  | 490 | goto out_mutex; | 
|  | 491 | } | 
|  | 492 |  | 
|  | 493 | fe = (struct ocfs2_dinode *)main_bm_bh->b_data; | 
|  | 494 |  | 
|  | 495 | if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != | 
| Tao Ma | 8571882 | 2010-04-13 14:38:06 +0800 | [diff] [blame] | 496 | ocfs2_group_bitmap_size(osb->sb, 0, | 
|  | 497 | osb->s_feature_incompat) * 8) { | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 498 | mlog(ML_ERROR, "The disk is too old and small." | 
|  | 499 | " Force to do offline resize."); | 
|  | 500 | ret = -EINVAL; | 
|  | 501 | goto out_unlock; | 
|  | 502 | } | 
|  | 503 |  | 
| Joel Becker | da1e909 | 2008-10-09 17:20:29 -0700 | [diff] [blame] | 504 | ret = ocfs2_read_blocks_sync(osb, input->group, 1, &group_bh); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 505 | if (ret < 0) { | 
|  | 506 | mlog(ML_ERROR, "Can't read the group descriptor # %llu " | 
|  | 507 | "from the device.", (unsigned long long)input->group); | 
|  | 508 | goto out_unlock; | 
|  | 509 | } | 
|  | 510 |  | 
| Joel Becker | 8cb471e | 2009-02-10 20:00:41 -0800 | [diff] [blame] | 511 | ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 512 |  | 
|  | 513 | ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); | 
|  | 514 | if (ret) { | 
|  | 515 | mlog_errno(ret); | 
|  | 516 | goto out_unlock; | 
|  | 517 | } | 
|  | 518 |  | 
| Tao Ma | a543870 | 2011-02-22 08:24:01 +0800 | [diff] [blame] | 519 | trace_ocfs2_group_add((unsigned long long)input->group, | 
|  | 520 | input->chain, input->clusters, input->frees); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 521 |  | 
|  | 522 | handle = ocfs2_start_trans(osb, OCFS2_GROUP_ADD_CREDITS); | 
|  | 523 | if (IS_ERR(handle)) { | 
|  | 524 | mlog_errno(PTR_ERR(handle)); | 
|  | 525 | ret = -EINVAL; | 
|  | 526 | goto out_unlock; | 
|  | 527 | } | 
|  | 528 |  | 
|  | 529 | cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); | 
|  | 530 | cl = &fe->id2.i_chain; | 
|  | 531 | cr = &cl->cl_recs[input->chain]; | 
|  | 532 |  | 
| Joel Becker | 0cf2f76 | 2009-02-12 16:41:25 -0800 | [diff] [blame] | 533 | ret = ocfs2_journal_access_gd(handle, INODE_CACHE(main_bm_inode), | 
|  | 534 | group_bh, OCFS2_JOURNAL_ACCESS_WRITE); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 535 | if (ret < 0) { | 
|  | 536 | mlog_errno(ret); | 
|  | 537 | goto out_commit; | 
|  | 538 | } | 
|  | 539 |  | 
|  | 540 | group = (struct ocfs2_group_desc *)group_bh->b_data; | 
|  | 541 | group->bg_next_group = cr->c_blkno; | 
| Joel Becker | ec20cec | 2010-03-19 14:13:52 -0700 | [diff] [blame] | 542 | ocfs2_journal_dirty(handle, group_bh); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 543 |  | 
| Joel Becker | 0cf2f76 | 2009-02-12 16:41:25 -0800 | [diff] [blame] | 544 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(main_bm_inode), | 
|  | 545 | main_bm_bh, OCFS2_JOURNAL_ACCESS_WRITE); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 546 | if (ret < 0) { | 
|  | 547 | mlog_errno(ret); | 
|  | 548 | goto out_commit; | 
|  | 549 | } | 
|  | 550 |  | 
|  | 551 | if (input->chain == le16_to_cpu(cl->cl_next_free_rec)) { | 
|  | 552 | le16_add_cpu(&cl->cl_next_free_rec, 1); | 
|  | 553 | memset(cr, 0, sizeof(struct ocfs2_chain_rec)); | 
|  | 554 | } | 
|  | 555 |  | 
| Tao Ma | 4338ab6 | 2008-03-03 10:53:02 +0800 | [diff] [blame] | 556 | cr->c_blkno = cpu_to_le64(input->group); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 557 | le32_add_cpu(&cr->c_total, input->clusters * cl_bpc); | 
|  | 558 | le32_add_cpu(&cr->c_free, input->frees * cl_bpc); | 
|  | 559 |  | 
|  | 560 | le32_add_cpu(&fe->id1.bitmap1.i_total, input->clusters *cl_bpc); | 
|  | 561 | le32_add_cpu(&fe->id1.bitmap1.i_used, | 
|  | 562 | (input->clusters - input->frees) * cl_bpc); | 
|  | 563 | le32_add_cpu(&fe->i_clusters, input->clusters); | 
|  | 564 |  | 
|  | 565 | ocfs2_journal_dirty(handle, main_bm_bh); | 
|  | 566 |  | 
|  | 567 | spin_lock(&OCFS2_I(main_bm_inode)->ip_lock); | 
|  | 568 | OCFS2_I(main_bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters); | 
|  | 569 | le64_add_cpu(&fe->i_size, input->clusters << osb->s_clustersize_bits); | 
|  | 570 | spin_unlock(&OCFS2_I(main_bm_inode)->ip_lock); | 
|  | 571 | i_size_write(main_bm_inode, le64_to_cpu(fe->i_size)); | 
|  | 572 |  | 
|  | 573 | ocfs2_update_super_and_backups(main_bm_inode, input->clusters); | 
|  | 574 |  | 
|  | 575 | out_commit: | 
|  | 576 | ocfs2_commit_trans(osb, handle); | 
|  | 577 | out_unlock: | 
| Mark Fasheh | 2fe5c1d | 2008-01-23 18:35:31 -0800 | [diff] [blame] | 578 | brelse(group_bh); | 
|  | 579 | brelse(main_bm_bh); | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 580 |  | 
|  | 581 | ocfs2_inode_unlock(main_bm_inode, 1); | 
|  | 582 |  | 
|  | 583 | out_mutex: | 
|  | 584 | mutex_unlock(&main_bm_inode->i_mutex); | 
|  | 585 | iput(main_bm_inode); | 
|  | 586 |  | 
|  | 587 | out: | 
| Tao Ma | 7909f2b | 2007-12-18 15:47:25 +0800 | [diff] [blame] | 588 | return ret; | 
|  | 589 | } |