Deleted Added
full compact
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 != &marker; 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 != &marker; 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 ---