dnode_sync.c (177698) | dnode_sync.c (185029) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 5 unchanged lines hidden (view full) --- 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 5 unchanged lines hidden (view full) --- 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* |
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
23 * Use is subject to license terms. 24 */ 25 26#pragma ident "%Z%%M% %I% %E% SMI" 27 28#include <sys/zfs_context.h> 29#include <sys/dbuf.h> 30#include <sys/dnode.h> --- 19 unchanged lines hidden (view full) --- 50 ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE); 51 ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock)); 52 ASSERT(new_level > 1 && dn->dn_phys->dn_nlevels > 0); 53 54 db = dbuf_hold_level(dn, dn->dn_phys->dn_nlevels, 0, FTAG); 55 ASSERT(db != NULL); 56 57 dn->dn_phys->dn_nlevels = new_level; | 23 * Use is subject to license terms. 24 */ 25 26#pragma ident "%Z%%M% %I% %E% SMI" 27 28#include <sys/zfs_context.h> 29#include <sys/dbuf.h> 30#include <sys/dnode.h> --- 19 unchanged lines hidden (view full) --- 50 ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE); 51 ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock)); 52 ASSERT(new_level > 1 && dn->dn_phys->dn_nlevels > 0); 53 54 db = dbuf_hold_level(dn, dn->dn_phys->dn_nlevels, 0, FTAG); 55 ASSERT(db != NULL); 56 57 dn->dn_phys->dn_nlevels = new_level; |
58 dprintf("os=%p obj=%llu, increase to %d\n", 59 dn->dn_objset, dn->dn_object, 60 dn->dn_phys->dn_nlevels); | 58 dprintf("os=%p obj=%llu, increase to %d\n", dn->dn_objset, 59 dn->dn_object, dn->dn_phys->dn_nlevels); |
61 62 /* check for existing blkptrs in the dnode */ 63 for (i = 0; i < nblkptr; i++) 64 if (!BP_IS_HOLE(&dn->dn_phys->dn_blkptr[i])) 65 break; 66 if (i != nblkptr) { 67 /* transfer dnode's block pointers to new indirect block */ 68 (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED|DB_RF_HAVESTRUCT); --- 36 unchanged lines hidden (view full) --- 105 106 bzero(dn->dn_phys->dn_blkptr, sizeof (blkptr_t) * nblkptr); 107 108 dbuf_rele(db, FTAG); 109 110 rw_exit(&dn->dn_struct_rwlock); 111} 112 | 60 61 /* check for existing blkptrs in the dnode */ 62 for (i = 0; i < nblkptr; i++) 63 if (!BP_IS_HOLE(&dn->dn_phys->dn_blkptr[i])) 64 break; 65 if (i != nblkptr) { 66 /* transfer dnode's block pointers to new indirect block */ 67 (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED|DB_RF_HAVESTRUCT); --- 36 unchanged lines hidden (view full) --- 104 105 bzero(dn->dn_phys->dn_blkptr, sizeof (blkptr_t) * nblkptr); 106 107 dbuf_rele(db, FTAG); 108 109 rw_exit(&dn->dn_struct_rwlock); 110} 111 |
113static void | 112static int |
114free_blocks(dnode_t *dn, blkptr_t *bp, int num, dmu_tx_t *tx) 115{ | 113free_blocks(dnode_t *dn, blkptr_t *bp, int num, dmu_tx_t *tx) 114{ |
116 objset_impl_t *os = dn->dn_objset; | 115 dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset; |
117 uint64_t bytesfreed = 0; | 116 uint64_t bytesfreed = 0; |
118 int i; | 117 int i, blocks_freed = 0; |
119 | 118 |
120 dprintf("os=%p obj=%llx num=%d\n", os, dn->dn_object, num); | 119 dprintf("ds=%p obj=%llx num=%d\n", ds, dn->dn_object, num); |
121 122 for (i = 0; i < num; i++, bp++) { 123 if (BP_IS_HOLE(bp)) 124 continue; 125 | 120 121 for (i = 0; i < num; i++, bp++) { 122 if (BP_IS_HOLE(bp)) 123 continue; 124 |
126 bytesfreed += bp_get_dasize(os->os_spa, bp); | 125 bytesfreed += dsl_dataset_block_kill(ds, bp, dn->dn_zio, tx); |
127 ASSERT3U(bytesfreed, <=, DN_USED_BYTES(dn->dn_phys)); | 126 ASSERT3U(bytesfreed, <=, DN_USED_BYTES(dn->dn_phys)); |
128 dsl_dataset_block_kill(os->os_dsl_dataset, bp, dn->dn_zio, tx); | |
129 bzero(bp, sizeof (blkptr_t)); | 127 bzero(bp, sizeof (blkptr_t)); |
128 blocks_freed += 1; |
|
130 } 131 dnode_diduse_space(dn, -bytesfreed); | 129 } 130 dnode_diduse_space(dn, -bytesfreed); |
131 return (blocks_freed); |
|
132} 133 134#ifdef ZFS_DEBUG 135static void 136free_verify(dmu_buf_impl_t *db, uint64_t start, uint64_t end, dmu_tx_t *tx) 137{ 138 int off, num; 139 int i, err, epbs; --- 15 unchanged lines hidden (view full) --- 155 dmu_buf_impl_t *child; 156 dbuf_dirty_record_t *dr; 157 int j; 158 159 ASSERT(db->db_level == 1); 160 161 rw_enter(&db->db_dnode->dn_struct_rwlock, RW_READER); 162 err = dbuf_hold_impl(db->db_dnode, db->db_level-1, | 132} 133 134#ifdef ZFS_DEBUG 135static void 136free_verify(dmu_buf_impl_t *db, uint64_t start, uint64_t end, dmu_tx_t *tx) 137{ 138 int off, num; 139 int i, err, epbs; --- 15 unchanged lines hidden (view full) --- 155 dmu_buf_impl_t *child; 156 dbuf_dirty_record_t *dr; 157 int j; 158 159 ASSERT(db->db_level == 1); 160 161 rw_enter(&db->db_dnode->dn_struct_rwlock, RW_READER); 162 err = dbuf_hold_impl(db->db_dnode, db->db_level-1, |
163 (db->db_blkid << epbs) + i, TRUE, FTAG, &child); | 163 (db->db_blkid << epbs) + i, TRUE, FTAG, &child); |
164 rw_exit(&db->db_dnode->dn_struct_rwlock); 165 if (err == ENOENT) 166 continue; 167 ASSERT(err == 0); 168 ASSERT(child->db_level == 0); 169 dr = child->db_last_dirty; 170 while (dr && dr->dr_txg > txg) 171 dr = dr->dr_next; 172 ASSERT(dr == NULL || dr->dr_txg == txg); 173 174 /* data_old better be zeroed */ 175 if (dr) { 176 buf = dr->dt.dl.dr_data->b_data; 177 for (j = 0; j < child->db.db_size >> 3; j++) { 178 if (buf[j] != 0) { 179 panic("freed data not zero: " 180 "child=%p i=%d off=%d num=%d\n", | 164 rw_exit(&db->db_dnode->dn_struct_rwlock); 165 if (err == ENOENT) 166 continue; 167 ASSERT(err == 0); 168 ASSERT(child->db_level == 0); 169 dr = child->db_last_dirty; 170 while (dr && dr->dr_txg > txg) 171 dr = dr->dr_next; 172 ASSERT(dr == NULL || dr->dr_txg == txg); 173 174 /* data_old better be zeroed */ 175 if (dr) { 176 buf = dr->dt.dl.dr_data->b_data; 177 for (j = 0; j < child->db.db_size >> 3; j++) { 178 if (buf[j] != 0) { 179 panic("freed data not zero: " 180 "child=%p i=%d off=%d num=%d\n", |
181 child, i, off, num); | 181 (void *)child, i, off, num); |
182 } 183 } 184 } 185 186 /* 187 * db_data better be zeroed unless it's dirty in a 188 * future txg. 189 */ 190 mutex_enter(&child->db_mtx); 191 buf = child->db.db_data; 192 if (buf != NULL && child->db_state != DB_FILL && 193 child->db_last_dirty == NULL) { 194 for (j = 0; j < child->db.db_size >> 3; j++) { 195 if (buf[j] != 0) { 196 panic("freed data not zero: " 197 "child=%p i=%d off=%d num=%d\n", | 182 } 183 } 184 } 185 186 /* 187 * db_data better be zeroed unless it's dirty in a 188 * future txg. 189 */ 190 mutex_enter(&child->db_mtx); 191 buf = child->db.db_data; 192 if (buf != NULL && child->db_state != DB_FILL && 193 child->db_last_dirty == NULL) { 194 for (j = 0; j < child->db.db_size >> 3; j++) { 195 if (buf[j] != 0) { 196 panic("freed data not zero: " 197 "child=%p i=%d off=%d num=%d\n", |
198 child, i, off, num); | 198 (void *)child, i, off, num); |
199 } 200 } 201 } 202 mutex_exit(&child->db_mtx); 203 204 dbuf_rele(child, FTAG); 205 } 206} 207#endif 208 | 199 } 200 } 201 } 202 mutex_exit(&child->db_mtx); 203 204 dbuf_rele(child, FTAG); 205 } 206} 207#endif 208 |
209#define ALL -1 210 |
|
209static int 210free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks, int trunc, 211 dmu_tx_t *tx) 212{ 213 dnode_t *dn = db->db_dnode; 214 blkptr_t *bp; 215 dmu_buf_impl_t *subdb; 216 uint64_t start, end, dbstart, dbend, i; 217 int epbs, shift, err; 218 int all = TRUE; | 211static int 212free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks, int trunc, 213 dmu_tx_t *tx) 214{ 215 dnode_t *dn = db->db_dnode; 216 blkptr_t *bp; 217 dmu_buf_impl_t *subdb; 218 uint64_t start, end, dbstart, dbend, i; 219 int epbs, shift, err; 220 int all = TRUE; |
221 int blocks_freed = 0; |
|
219 | 222 |
220 (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED); | 223 /* 224 * There is a small possibility that this block will not be cached: 225 * 1 - if level > 1 and there are no children with level <= 1 226 * 2 - if we didn't get a dirty hold (because this block had just 227 * finished being written -- and so had no holds), and then this 228 * block got evicted before we got here. 229 */ 230 if (db->db_state != DB_CACHED) 231 (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED); 232 |
221 arc_release(db->db_buf, db); 222 bp = (blkptr_t *)db->db.db_data; 223 224 epbs = db->db_dnode->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; 225 shift = (db->db_level - 1) * epbs; 226 dbstart = db->db_blkid << epbs; 227 start = blkid >> shift; 228 if (dbstart < start) { --- 7 unchanged lines hidden (view full) --- 236 if (dbend <= end) 237 end = dbend; 238 else if (all) 239 all = trunc; 240 ASSERT3U(start, <=, end); 241 242 if (db->db_level == 1) { 243 FREE_VERIFY(db, start, end, tx); | 233 arc_release(db->db_buf, db); 234 bp = (blkptr_t *)db->db.db_data; 235 236 epbs = db->db_dnode->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; 237 shift = (db->db_level - 1) * epbs; 238 dbstart = db->db_blkid << epbs; 239 start = blkid >> shift; 240 if (dbstart < start) { --- 7 unchanged lines hidden (view full) --- 248 if (dbend <= end) 249 end = dbend; 250 else if (all) 251 all = trunc; 252 ASSERT3U(start, <=, end); 253 254 if (db->db_level == 1) { 255 FREE_VERIFY(db, start, end, tx); |
244 free_blocks(dn, bp, end-start+1, tx); | 256 blocks_freed = free_blocks(dn, bp, end-start+1, tx); |
245 arc_buf_freeze(db->db_buf); | 257 arc_buf_freeze(db->db_buf); |
246 ASSERT(all || db->db_last_dirty); 247 return (all); | 258 ASSERT(all || blocks_freed == 0 || db->db_last_dirty); 259 return (all ? ALL : blocks_freed); |
248 } 249 250 for (i = start; i <= end; i++, bp++) { 251 if (BP_IS_HOLE(bp)) 252 continue; 253 rw_enter(&dn->dn_struct_rwlock, RW_READER); 254 err = dbuf_hold_impl(dn, db->db_level-1, i, TRUE, FTAG, &subdb); 255 ASSERT3U(err, ==, 0); 256 rw_exit(&dn->dn_struct_rwlock); 257 | 260 } 261 262 for (i = start; i <= end; i++, bp++) { 263 if (BP_IS_HOLE(bp)) 264 continue; 265 rw_enter(&dn->dn_struct_rwlock, RW_READER); 266 err = dbuf_hold_impl(dn, db->db_level-1, i, TRUE, FTAG, &subdb); 267 ASSERT3U(err, ==, 0); 268 rw_exit(&dn->dn_struct_rwlock); 269 |
258 if (free_children(subdb, blkid, nblks, trunc, tx)) { | 270 if (free_children(subdb, blkid, nblks, trunc, tx) == ALL) { |
259 ASSERT3P(subdb->db_blkptr, ==, bp); | 271 ASSERT3P(subdb->db_blkptr, ==, bp); |
260 free_blocks(dn, bp, 1, tx); | 272 blocks_freed += free_blocks(dn, bp, 1, tx); |
261 } else { 262 all = FALSE; 263 } 264 dbuf_rele(subdb, FTAG); 265 } 266 arc_buf_freeze(db->db_buf); 267#ifdef ZFS_DEBUG 268 bp -= (end-start)+1; 269 for (i = start; i <= end; i++, bp++) { 270 if (i == start && blkid != 0) 271 continue; 272 else if (i == end && !trunc) 273 continue; 274 ASSERT3U(bp->blk_birth, ==, 0); 275 } 276#endif | 273 } else { 274 all = FALSE; 275 } 276 dbuf_rele(subdb, FTAG); 277 } 278 arc_buf_freeze(db->db_buf); 279#ifdef ZFS_DEBUG 280 bp -= (end-start)+1; 281 for (i = start; i <= end; i++, bp++) { 282 if (i == start && blkid != 0) 283 continue; 284 else if (i == end && !trunc) 285 continue; 286 ASSERT3U(bp->blk_birth, ==, 0); 287 } 288#endif |
277 ASSERT(all || db->db_last_dirty); 278 return (all); | 289 ASSERT(all || blocks_freed == 0 || db->db_last_dirty); 290 return (all ? ALL : blocks_freed); |
279} 280 281/* 282 * free_range: Traverse the indicated range of the provided file 283 * and "free" all the blocks contained there. 284 */ 285static void 286dnode_sync_free_range(dnode_t *dn, uint64_t blkid, uint64_t nblks, dmu_tx_t *tx) --- 13 unchanged lines hidden (view full) --- 300 301 /* There are no indirect blocks in the object */ 302 if (dnlevel == 1) { 303 if (blkid >= dn->dn_phys->dn_nblkptr) { 304 /* this range was never made persistent */ 305 return; 306 } 307 ASSERT3U(blkid + nblks, <=, dn->dn_phys->dn_nblkptr); | 291} 292 293/* 294 * free_range: Traverse the indicated range of the provided file 295 * and "free" all the blocks contained there. 296 */ 297static void 298dnode_sync_free_range(dnode_t *dn, uint64_t blkid, uint64_t nblks, dmu_tx_t *tx) --- 13 unchanged lines hidden (view full) --- 312 313 /* There are no indirect blocks in the object */ 314 if (dnlevel == 1) { 315 if (blkid >= dn->dn_phys->dn_nblkptr) { 316 /* this range was never made persistent */ 317 return; 318 } 319 ASSERT3U(blkid + nblks, <=, dn->dn_phys->dn_nblkptr); |
308 free_blocks(dn, bp + blkid, nblks, tx); | 320 (void) free_blocks(dn, bp + blkid, nblks, tx); |
309 if (trunc) { 310 uint64_t off = (dn->dn_phys->dn_maxblkid + 1) * 311 (dn->dn_phys->dn_datablkszsec << SPA_MINBLOCKSHIFT); 312 dn->dn_phys->dn_maxblkid = (blkid ? blkid - 1 : 0); 313 ASSERT(off < dn->dn_phys->dn_maxblkid || 314 dn->dn_phys->dn_maxblkid == 0 || | 321 if (trunc) { 322 uint64_t off = (dn->dn_phys->dn_maxblkid + 1) * 323 (dn->dn_phys->dn_datablkszsec << SPA_MINBLOCKSHIFT); 324 dn->dn_phys->dn_maxblkid = (blkid ? blkid - 1 : 0); 325 ASSERT(off < dn->dn_phys->dn_maxblkid || 326 dn->dn_phys->dn_maxblkid == 0 || |
315 dnode_next_offset(dn, FALSE, &off, 316 1, 1, 0) != 0); | 327 dnode_next_offset(dn, 0, &off, 1, 1, 0) != 0); |
317 } 318 return; 319 } 320 321 shift = (dnlevel - 1) * (dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT); 322 start = blkid >> shift; 323 ASSERT(start < dn->dn_phys->dn_nblkptr); 324 end = (blkid + nblks - 1) >> shift; 325 bp += start; 326 for (i = start; i <= end; i++, bp++) { 327 if (BP_IS_HOLE(bp)) 328 continue; 329 rw_enter(&dn->dn_struct_rwlock, RW_READER); 330 err = dbuf_hold_impl(dn, dnlevel-1, i, TRUE, FTAG, &db); 331 ASSERT3U(err, ==, 0); 332 rw_exit(&dn->dn_struct_rwlock); 333 | 328 } 329 return; 330 } 331 332 shift = (dnlevel - 1) * (dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT); 333 start = blkid >> shift; 334 ASSERT(start < dn->dn_phys->dn_nblkptr); 335 end = (blkid + nblks - 1) >> shift; 336 bp += start; 337 for (i = start; i <= end; i++, bp++) { 338 if (BP_IS_HOLE(bp)) 339 continue; 340 rw_enter(&dn->dn_struct_rwlock, RW_READER); 341 err = dbuf_hold_impl(dn, dnlevel-1, i, TRUE, FTAG, &db); 342 ASSERT3U(err, ==, 0); 343 rw_exit(&dn->dn_struct_rwlock); 344 |
334 if (free_children(db, blkid, nblks, trunc, tx)) { | 345 if (free_children(db, blkid, nblks, trunc, tx) == ALL) { |
335 ASSERT3P(db->db_blkptr, ==, bp); | 346 ASSERT3P(db->db_blkptr, ==, bp); |
336 free_blocks(dn, bp, 1, tx); | 347 (void) free_blocks(dn, bp, 1, tx); |
337 } 338 dbuf_rele(db, FTAG); 339 } 340 if (trunc) { 341 uint64_t off = (dn->dn_phys->dn_maxblkid + 1) * 342 (dn->dn_phys->dn_datablkszsec << SPA_MINBLOCKSHIFT); 343 dn->dn_phys->dn_maxblkid = (blkid ? blkid - 1 : 0); 344 ASSERT(off < dn->dn_phys->dn_maxblkid || 345 dn->dn_phys->dn_maxblkid == 0 || | 348 } 349 dbuf_rele(db, FTAG); 350 } 351 if (trunc) { 352 uint64_t off = (dn->dn_phys->dn_maxblkid + 1) * 353 (dn->dn_phys->dn_datablkszsec << SPA_MINBLOCKSHIFT); 354 dn->dn_phys->dn_maxblkid = (blkid ? blkid - 1 : 0); 355 ASSERT(off < dn->dn_phys->dn_maxblkid || 356 dn->dn_phys->dn_maxblkid == 0 || |
346 dnode_next_offset(dn, FALSE, &off, 1, 1, 0) != 0); | 357 dnode_next_offset(dn, 0, &off, 1, 1, 0) != 0); |
347 } 348} 349 350/* 351 * Try to kick all the dnodes dbufs out of the cache... 352 */ | 358 } 359} 360 361/* 362 * Try to kick all the dnodes dbufs out of the cache... 363 */ |
353int 354dnode_evict_dbufs(dnode_t *dn, int try) | 364void 365dnode_evict_dbufs(dnode_t *dn) |
355{ 356 int progress; 357 int pass = 0; 358 359 do { 360 dmu_buf_impl_t *db, marker; 361 int evicting = FALSE; 362 363 progress = FALSE; 364 mutex_enter(&dn->dn_dbufs_mtx); 365 list_insert_tail(&dn->dn_dbufs, &marker); 366 db = list_head(&dn->dn_dbufs); 367 for (; db != ▮ db = list_head(&dn->dn_dbufs)) { 368 list_remove(&dn->dn_dbufs, db); 369 list_insert_tail(&dn->dn_dbufs, db); | 366{ 367 int progress; 368 int pass = 0; 369 370 do { 371 dmu_buf_impl_t *db, marker; 372 int evicting = FALSE; 373 374 progress = FALSE; 375 mutex_enter(&dn->dn_dbufs_mtx); 376 list_insert_tail(&dn->dn_dbufs, &marker); 377 db = list_head(&dn->dn_dbufs); 378 for (; db != ▮ db = list_head(&dn->dn_dbufs)) { 379 list_remove(&dn->dn_dbufs, db); 380 list_insert_tail(&dn->dn_dbufs, db); |
381 ASSERT3P(db->db_dnode, ==, dn); |
|
370 371 mutex_enter(&db->db_mtx); 372 if (db->db_state == DB_EVICTING) { 373 progress = TRUE; 374 evicting = TRUE; 375 mutex_exit(&db->db_mtx); 376 } else if (refcount_is_zero(&db->db_holds)) { 377 progress = TRUE; | 382 383 mutex_enter(&db->db_mtx); 384 if (db->db_state == DB_EVICTING) { 385 progress = TRUE; 386 evicting = TRUE; 387 mutex_exit(&db->db_mtx); 388 } else if (refcount_is_zero(&db->db_holds)) { 389 progress = TRUE; |
378 ASSERT(!arc_released(db->db_buf)); | |
379 dbuf_clear(db); /* exits db_mtx for us */ 380 } else { 381 mutex_exit(&db->db_mtx); 382 } 383 384 } 385 list_remove(&dn->dn_dbufs, &marker); 386 /* --- 5 unchanged lines hidden (view full) --- 392 */ 393 mutex_exit(&dn->dn_dbufs_mtx); 394 if (evicting) 395 delay(1); 396 pass++; 397 ASSERT(pass < 100); /* sanity check */ 398 } while (progress); 399 | 390 dbuf_clear(db); /* exits db_mtx for us */ 391 } else { 392 mutex_exit(&db->db_mtx); 393 } 394 395 } 396 list_remove(&dn->dn_dbufs, &marker); 397 /* --- 5 unchanged lines hidden (view full) --- 403 */ 404 mutex_exit(&dn->dn_dbufs_mtx); 405 if (evicting) 406 delay(1); 407 pass++; 408 ASSERT(pass < 100); /* sanity check */ 409 } while (progress); 410 |
400 /* 401 * This function works fine even if it can't evict everything. 402 * If were only asked to try to evict everything then 403 * return an error if we can't. Otherwise panic as the caller 404 * expects total eviction. 405 */ 406 if (list_head(&dn->dn_dbufs) != NULL) { 407 if (try) { 408 return (1); 409 } else { 410 panic("dangling dbufs (dn=%p, dbuf=%p)\n", 411 dn, list_head(&dn->dn_dbufs)); 412 } 413 } 414 | |
415 rw_enter(&dn->dn_struct_rwlock, RW_WRITER); 416 if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) { 417 mutex_enter(&dn->dn_bonus->db_mtx); 418 dbuf_evict(dn->dn_bonus); 419 dn->dn_bonus = NULL; 420 } 421 rw_exit(&dn->dn_struct_rwlock); | 411 rw_enter(&dn->dn_struct_rwlock, RW_WRITER); 412 if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) { 413 mutex_enter(&dn->dn_bonus->db_mtx); 414 dbuf_evict(dn->dn_bonus); 415 dn->dn_bonus = NULL; 416 } 417 rw_exit(&dn->dn_struct_rwlock); |
422 return (0); | |
423} 424 425static void 426dnode_undirty_dbufs(list_t *list) 427{ 428 dbuf_dirty_record_t *dr; 429 430 while (dr = list_head(list)) { --- 24 unchanged lines hidden (view full) --- 455 456static void 457dnode_sync_free(dnode_t *dn, dmu_tx_t *tx) 458{ 459 int txgoff = tx->tx_txg & TXG_MASK; 460 461 ASSERT(dmu_tx_is_syncing(tx)); 462 | 418} 419 420static void 421dnode_undirty_dbufs(list_t *list) 422{ 423 dbuf_dirty_record_t *dr; 424 425 while (dr = list_head(list)) { --- 24 unchanged lines hidden (view full) --- 450 451static void 452dnode_sync_free(dnode_t *dn, dmu_tx_t *tx) 453{ 454 int txgoff = tx->tx_txg & TXG_MASK; 455 456 ASSERT(dmu_tx_is_syncing(tx)); 457 |
458 /* 459 * Our contents should have been freed in dnode_sync() by the 460 * free range record inserted by the caller of dnode_free(). 461 */ 462 ASSERT3U(DN_USED_BYTES(dn->dn_phys), ==, 0); 463 ASSERT(BP_IS_HOLE(dn->dn_phys->dn_blkptr)); 464 |
|
463 dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]); | 465 dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]); |
464 (void) dnode_evict_dbufs(dn, 0); | 466 dnode_evict_dbufs(dn); |
465 ASSERT3P(list_head(&dn->dn_dbufs), ==, NULL); 466 467 /* 468 * XXX - It would be nice to assert this, but we may still 469 * have residual holds from async evictions from the arc... 470 * 471 * zfs_obj_to_path() also depends on this being 472 * commented out. 473 * 474 * ASSERT3U(refcount_count(&dn->dn_holds), ==, 1); 475 */ 476 477 /* Undirty next bits */ 478 dn->dn_next_nlevels[txgoff] = 0; 479 dn->dn_next_indblkshift[txgoff] = 0; 480 dn->dn_next_blksz[txgoff] = 0; 481 | 467 ASSERT3P(list_head(&dn->dn_dbufs), ==, NULL); 468 469 /* 470 * XXX - It would be nice to assert this, but we may still 471 * have residual holds from async evictions from the arc... 472 * 473 * zfs_obj_to_path() also depends on this being 474 * commented out. 475 * 476 * ASSERT3U(refcount_count(&dn->dn_holds), ==, 1); 477 */ 478 479 /* Undirty next bits */ 480 dn->dn_next_nlevels[txgoff] = 0; 481 dn->dn_next_indblkshift[txgoff] = 0; 482 dn->dn_next_blksz[txgoff] = 0; 483 |
482 /* free up all the blocks in the file. */ 483 dnode_sync_free_range(dn, 0, dn->dn_phys->dn_maxblkid+1, tx); 484 ASSERT3U(DN_USED_BYTES(dn->dn_phys), ==, 0); 485 | |
486 /* ASSERT(blkptrs are zero); */ 487 ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE); 488 ASSERT(dn->dn_type != DMU_OT_NONE); 489 490 ASSERT(dn->dn_free_txg > 0); 491 if (dn->dn_allocated_txg != dn->dn_free_txg) 492 dbuf_will_dirty(dn->dn_dbuf, tx); 493 bzero(dn->dn_phys, sizeof (dnode_phys_t)); 494 495 mutex_enter(&dn->dn_mtx); 496 dn->dn_type = DMU_OT_NONE; 497 dn->dn_maxblkid = 0; 498 dn->dn_allocated_txg = 0; | 484 /* ASSERT(blkptrs are zero); */ 485 ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE); 486 ASSERT(dn->dn_type != DMU_OT_NONE); 487 488 ASSERT(dn->dn_free_txg > 0); 489 if (dn->dn_allocated_txg != dn->dn_free_txg) 490 dbuf_will_dirty(dn->dn_dbuf, tx); 491 bzero(dn->dn_phys, sizeof (dnode_phys_t)); 492 493 mutex_enter(&dn->dn_mtx); 494 dn->dn_type = DMU_OT_NONE; 495 dn->dn_maxblkid = 0; 496 dn->dn_allocated_txg = 0; |
497 dn->dn_free_txg = 0; |
|
499 mutex_exit(&dn->dn_mtx); 500 501 ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT); 502 503 dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg); 504 /* 505 * Now that we've released our hold, the dnode may 506 * be evicted, so we musn't access it. --- 46 unchanged lines hidden (view full) --- 553 BP_IS_HOLE(&dnp->dn_blkptr[0]) || 554 BP_GET_LSIZE(&dnp->dn_blkptr[0]) == 555 dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT); 556 557 if (dn->dn_next_blksz[txgoff]) { 558 ASSERT(P2PHASE(dn->dn_next_blksz[txgoff], 559 SPA_MINBLOCKSIZE) == 0); 560 ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) || | 498 mutex_exit(&dn->dn_mtx); 499 500 ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT); 501 502 dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg); 503 /* 504 * Now that we've released our hold, the dnode may 505 * be evicted, so we musn't access it. --- 46 unchanged lines hidden (view full) --- 552 BP_IS_HOLE(&dnp->dn_blkptr[0]) || 553 BP_GET_LSIZE(&dnp->dn_blkptr[0]) == 554 dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT); 555 556 if (dn->dn_next_blksz[txgoff]) { 557 ASSERT(P2PHASE(dn->dn_next_blksz[txgoff], 558 SPA_MINBLOCKSIZE) == 0); 559 ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) || |
561 list_head(list) != NULL || | 560 dn->dn_maxblkid == 0 || list_head(list) != NULL || |
562 dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT == 563 dnp->dn_datablkszsec); 564 dnp->dn_datablkszsec = 565 dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT; 566 dn->dn_next_blksz[txgoff] = 0; 567 } 568 | 561 dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT == 562 dnp->dn_datablkszsec); 563 dnp->dn_datablkszsec = 564 dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT; 565 dn->dn_next_blksz[txgoff] = 0; 566 } 567 |
568 if (dn->dn_next_bonuslen[txgoff]) { 569 if (dn->dn_next_bonuslen[txgoff] == DN_ZERO_BONUSLEN) 570 dnp->dn_bonuslen = 0; 571 else 572 dnp->dn_bonuslen = dn->dn_next_bonuslen[txgoff]; 573 ASSERT(dnp->dn_bonuslen <= DN_MAX_BONUSLEN); 574 dn->dn_next_bonuslen[txgoff] = 0; 575 } 576 |
|
569 if (dn->dn_next_indblkshift[txgoff]) { 570 ASSERT(dnp->dn_nlevels == 1); 571 dnp->dn_indblkshift = dn->dn_next_indblkshift[txgoff]; 572 dn->dn_next_indblkshift[txgoff] = 0; 573 } 574 575 /* 576 * Just take the live (open-context) values for checksum and compress. 577 * Strictly speaking it's a future leak, but nothing bad happens if we 578 * start using the new checksum or compress algorithm a little early. 579 */ 580 dnp->dn_checksum = dn->dn_checksum; 581 dnp->dn_compress = dn->dn_compress; 582 583 mutex_exit(&dn->dn_mtx); 584 585 /* process all the "freed" ranges in the file */ | 577 if (dn->dn_next_indblkshift[txgoff]) { 578 ASSERT(dnp->dn_nlevels == 1); 579 dnp->dn_indblkshift = dn->dn_next_indblkshift[txgoff]; 580 dn->dn_next_indblkshift[txgoff] = 0; 581 } 582 583 /* 584 * Just take the live (open-context) values for checksum and compress. 585 * Strictly speaking it's a future leak, but nothing bad happens if we 586 * start using the new checksum or compress algorithm a little early. 587 */ 588 dnp->dn_checksum = dn->dn_checksum; 589 dnp->dn_compress = dn->dn_compress; 590 591 mutex_exit(&dn->dn_mtx); 592 593 /* process all the "freed" ranges in the file */ |
586 if (dn->dn_free_txg == 0 || dn->dn_free_txg > tx->tx_txg) { 587 for (rp = avl_last(&dn->dn_ranges[txgoff]); rp != NULL; 588 rp = AVL_PREV(&dn->dn_ranges[txgoff], rp)) 589 dnode_sync_free_range(dn, 590 rp->fr_blkid, rp->fr_nblks, tx); | 594 while (rp = avl_last(&dn->dn_ranges[txgoff])) { 595 dnode_sync_free_range(dn, rp->fr_blkid, rp->fr_nblks, tx); 596 /* grab the mutex so we don't race with dnode_block_freed() */ 597 mutex_enter(&dn->dn_mtx); 598 avl_remove(&dn->dn_ranges[txgoff], rp); 599 mutex_exit(&dn->dn_mtx); 600 kmem_free(rp, sizeof (free_range_t)); |
591 } | 601 } |
592 mutex_enter(&dn->dn_mtx); 593 for (rp = avl_first(&dn->dn_ranges[txgoff]); rp; ) { 594 free_range_t *last = rp; 595 rp = AVL_NEXT(&dn->dn_ranges[txgoff], rp); 596 avl_remove(&dn->dn_ranges[txgoff], last); 597 kmem_free(last, sizeof (free_range_t)); 598 } 599 mutex_exit(&dn->dn_mtx); | |
600 601 if (dn->dn_free_txg > 0 && dn->dn_free_txg <= tx->tx_txg) { 602 dnode_sync_free(dn, tx); 603 return; 604 } 605 606 if (dn->dn_next_nlevels[txgoff]) { 607 dnode_increase_indirection(dn, tx); --- 16 unchanged lines hidden --- | 602 603 if (dn->dn_free_txg > 0 && dn->dn_free_txg <= tx->tx_txg) { 604 dnode_sync_free(dn, tx); 605 return; 606 } 607 608 if (dn->dn_next_nlevels[txgoff]) { 609 dnode_increase_indirection(dn, tx); --- 16 unchanged lines hidden --- |