xref: /dragonfly/sys/vfs/hammer2/hammer2_xops.c (revision 9ef1e017)
1 /*
2  * Copyright (c) 2011-2018 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7  * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression)
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 /*
37  * Per-node backend for kernel filesystem interface.
38  *
39  * This executes a VOP concurrently on multiple nodes, each node via its own
40  * thread, and competes to advance the original request.  The original
41  * request is retired the moment all requirements are met, even if the
42  * operation is still in-progress on some nodes.
43  */
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/proc.h>
48 #include <sys/mount.h>
49 
50 #include "hammer2.h"
51 
52 /*
53  * Determine if the specified directory is empty.
54  *
55  *	Returns 0 on success.
56  *
57  *	Returns HAMMER_ERROR_EAGAIN if caller must re-lookup the entry and
58  *	retry. (occurs if we race a ripup on oparent or ochain).
59  *
60  *	Or returns a permanent HAMMER2_ERROR_* error mask.
61  *
62  * The caller must pass in an exclusively locked oparent and ochain.  This
63  * function will handle the case where the chain is a directory entry or
64  * the inode itself.  The original oparent,ochain will be locked upon return.
65  *
66  * This function will unlock the underlying oparent,ochain temporarily when
67  * doing an inode lookup to avoid deadlocks.  The caller MUST handle the EAGAIN
68  * result as this means that oparent is no longer the parent of ochain, or
69  * that ochain was destroyed while it was unlocked.
70  */
71 static
72 int
73 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
74 {
75 	hammer2_chain_t *parent;
76 	hammer2_chain_t *chain;
77 	hammer2_key_t key_next;
78 	hammer2_key_t inum;
79 	int error;
80 	int didunlock;
81 
82 	error = 0;
83 	didunlock = 0;
84 
85 	/*
86 	 * Find the inode, set it up as a locked 'chain'.  ochain can be the
87 	 * inode itself, or it can be a directory entry.
88 	 */
89 	if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
90 		inum = ochain->bref.embed.dirent.inum;
91 		hammer2_chain_unlock(ochain);
92 		hammer2_chain_unlock(oparent);
93 
94 		parent = NULL;
95 		chain = NULL;
96 		error = hammer2_chain_inode_find(ochain->pmp, inum,
97 						 clindex, 0,
98 						 &parent, &chain);
99 		if (parent) {
100 			hammer2_chain_unlock(parent);
101 			hammer2_chain_drop(parent);
102 		}
103 		didunlock = 1;
104 	} else {
105 		/*
106 		 * The directory entry *is* the directory inode
107 		 */
108 		chain = hammer2_chain_lookup_init(ochain, 0);
109 	}
110 
111 	/*
112 	 * Determine if the directory is empty or not by checking its
113 	 * visible namespace (the area which contains directory entries).
114 	 */
115 	if (error == 0) {
116 		parent = chain;
117 		chain = NULL;
118 		if (parent) {
119 			chain = hammer2_chain_lookup(&parent, &key_next,
120 						     HAMMER2_DIRHASH_VISIBLE,
121 						     HAMMER2_KEY_MAX,
122 						     &error, 0);
123 		}
124 		if (chain) {
125 			error = HAMMER2_ERROR_ENOTEMPTY;
126 			hammer2_chain_unlock(chain);
127 			hammer2_chain_drop(chain);
128 		}
129 		hammer2_chain_lookup_done(parent);
130 	}
131 
132 	if (didunlock) {
133 		hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
134 		hammer2_chain_lock(ochain, HAMMER2_RESOLVE_ALWAYS);
135 		if ((ochain->flags & HAMMER2_CHAIN_DELETED) ||
136 		    (oparent->flags & HAMMER2_CHAIN_DELETED) ||
137 		    ochain->parent != oparent) {
138 			kprintf("hammer2: debug: CHECKDIR inum %jd RETRY\n",
139 				inum);
140 			error = HAMMER2_ERROR_EAGAIN;
141 		}
142 	}
143 	return error;
144 }
145 
146 /*
147  * Backend for hammer2_vfs_root()
148  *
149  * This is called when a newly mounted PFS has not yet synchronized
150  * to the inode_tid and modify_tid.
151  */
152 void
153 hammer2_xop_ipcluster(hammer2_xop_t *arg, void *scratch, int clindex)
154 {
155 	hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
156 	hammer2_chain_t *chain;
157 	int error;
158 
159 	chain = hammer2_inode_chain(xop->head.ip1, clindex,
160 				    HAMMER2_RESOLVE_ALWAYS |
161 				    HAMMER2_RESOLVE_SHARED);
162 	if (chain)
163 		error = chain->error;
164 	else
165 		error = HAMMER2_ERROR_EIO;
166 
167 	hammer2_xop_feed(&xop->head, chain, clindex, error);
168 	if (chain) {
169 		hammer2_chain_unlock(chain);
170 		hammer2_chain_drop(chain);
171 	}
172 }
173 
174 /*
175  * Backend for hammer2_vop_readdir()
176  */
177 void
178 hammer2_xop_readdir(hammer2_xop_t *arg, void *scratch, int clindex)
179 {
180 	hammer2_xop_readdir_t *xop = &arg->xop_readdir;
181 	hammer2_chain_t *parent;
182 	hammer2_chain_t *chain;
183 	hammer2_key_t key_next;
184 	hammer2_key_t lkey;
185 	int error = 0;
186 
187 	lkey = xop->lkey;
188 	if (hammer2_debug & 0x0020)
189 		kprintf("xop_readdir: %p lkey=%016jx\n", xop, lkey);
190 
191 	/*
192 	 * The inode's chain is the iterator.  If we cannot acquire it our
193 	 * contribution ends here.
194 	 */
195 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
196 				     HAMMER2_RESOLVE_ALWAYS |
197 				     HAMMER2_RESOLVE_SHARED);
198 	if (parent == NULL) {
199 		kprintf("xop_readdir: NULL parent\n");
200 		goto done;
201 	}
202 
203 	/*
204 	 * Directory scan [re]start and loop, the feed inherits the chain's
205 	 * lock so do not unlock it on the iteration.
206 	 */
207 	chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
208 				     &error, HAMMER2_LOOKUP_SHARED);
209 	if (chain == NULL) {
210 		chain = hammer2_chain_lookup(&parent, &key_next,
211 					     lkey, HAMMER2_KEY_MAX,
212 					     &error, HAMMER2_LOOKUP_SHARED);
213 	}
214 	while (chain) {
215 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
216 		if (error)
217 			goto break2;
218 		chain = hammer2_chain_next(&parent, chain, &key_next,
219 					   key_next, HAMMER2_KEY_MAX,
220 					   &error, HAMMER2_LOOKUP_SHARED);
221 	}
222 break2:
223 	if (chain) {
224 		hammer2_chain_unlock(chain);
225 		hammer2_chain_drop(chain);
226 	}
227 	hammer2_chain_unlock(parent);
228 	hammer2_chain_drop(parent);
229 done:
230 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
231 }
232 
233 /*
234  * Backend for hammer2_vop_nresolve()
235  */
236 void
237 hammer2_xop_nresolve(hammer2_xop_t *arg, void *scratch, int clindex)
238 {
239 	hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
240 	hammer2_chain_t *parent;
241 	hammer2_chain_t *chain;
242 	const char *name;
243 	size_t name_len;
244 	hammer2_key_t key_next;
245 	hammer2_key_t lhc;
246 	int error;
247 
248 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
249 				     HAMMER2_RESOLVE_ALWAYS |
250 				     HAMMER2_RESOLVE_SHARED);
251 	if (parent == NULL) {
252 		kprintf("xop_nresolve: NULL parent\n");
253 		chain = NULL;
254 		error = HAMMER2_ERROR_EIO;
255 		goto done;
256 	}
257 	name = xop->head.name1;
258 	name_len = xop->head.name1_len;
259 
260 	/*
261 	 * Lookup the directory entry
262 	 */
263 	lhc = hammer2_dirhash(name, name_len);
264 	chain = hammer2_chain_lookup(&parent, &key_next,
265 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
266 				     &error,
267 				     HAMMER2_LOOKUP_ALWAYS |
268 				     HAMMER2_LOOKUP_SHARED);
269 	while (chain) {
270 		if (hammer2_chain_dirent_test(chain, name, name_len))
271 			break;
272 		chain = hammer2_chain_next(&parent, chain, &key_next,
273 					   key_next,
274 					   lhc + HAMMER2_DIRHASH_LOMASK,
275 					   &error,
276 					   HAMMER2_LOOKUP_ALWAYS |
277 					   HAMMER2_LOOKUP_SHARED);
278 	}
279 
280 	/*
281 	 * Locate the target inode for a directory entry
282 	 */
283 	if (chain && chain->error == 0) {
284 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
285 			lhc = chain->bref.embed.dirent.inum;
286 			error = hammer2_chain_inode_find(chain->pmp,
287 							 lhc,
288 							 clindex,
289 							 HAMMER2_LOOKUP_SHARED,
290 							 &parent,
291 							 &chain);
292 		}
293 	} else if (chain && error == 0) {
294 		error = chain->error;
295 	}
296 done:
297 	error = hammer2_xop_feed(&xop->head, chain, clindex, error);
298 	if (chain) {
299 		hammer2_chain_unlock(chain);
300 		hammer2_chain_drop(chain);
301 	}
302 	if (parent) {
303 		hammer2_chain_unlock(parent);
304 		hammer2_chain_drop(parent);
305 	}
306 }
307 
308 /*
309  * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
310  * backend for pfs_delete.
311  *
312  * This function locates and removes a directory entry, and will lookup
313  * and return the underlying inode.  For directory entries the underlying
314  * inode is not removed.  If the directory entry is the actual inode itself,
315  * it may be conditonally removed and returned.
316  *
317  * WARNING!  Any target inode's nlinks may not be synchronized to the
318  *	     in-memory inode.  The frontend's hammer2_inode_unlink_finisher()
319  *	     is responsible for the final disposition of the actual inode.
320  */
321 void
322 hammer2_xop_unlink(hammer2_xop_t *arg, void *scratch, int clindex)
323 {
324 	hammer2_xop_unlink_t *xop = &arg->xop_unlink;
325 	hammer2_chain_t *parent;
326 	hammer2_chain_t *chain;
327 	const char *name;
328 	size_t name_len;
329 	hammer2_key_t key_next;
330 	hammer2_key_t lhc;
331 	int error;
332 
333 again:
334 	/*
335 	 * Requires exclusive lock
336 	 */
337 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
338 				     HAMMER2_RESOLVE_ALWAYS);
339 	chain = NULL;
340 	if (parent == NULL) {
341 		kprintf("xop_unlink: NULL parent\n");
342 		error = HAMMER2_ERROR_EIO;
343 		goto done;
344 	}
345 	name = xop->head.name1;
346 	name_len = xop->head.name1_len;
347 
348 	/*
349 	 * Lookup the directory entry
350 	 */
351 	lhc = hammer2_dirhash(name, name_len);
352 	chain = hammer2_chain_lookup(&parent, &key_next,
353 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
354 				     &error, HAMMER2_LOOKUP_ALWAYS);
355 	while (chain) {
356 		if (hammer2_chain_dirent_test(chain, name, name_len))
357 			break;
358 		chain = hammer2_chain_next(&parent, chain, &key_next,
359 					   key_next,
360 					   lhc + HAMMER2_DIRHASH_LOMASK,
361 					   &error, HAMMER2_LOOKUP_ALWAYS);
362 	}
363 
364 	/*
365 	 * The directory entry will either be a BREF_TYPE_DIRENT or a
366 	 * BREF_TYPE_INODE.  We always permanently delete DIRENTs, but
367 	 * must go by xop->dopermanent for BREF_TYPE_INODE.
368 	 *
369 	 * Note that the target chain's nlinks may not be synchronized with
370 	 * the in-memory hammer2_inode_t structure, so we don't try to do
371 	 * anything fancy here.  The frontend deals with nlinks
372 	 * synchronization.
373 	 */
374 	if (chain && chain->error == 0) {
375 		int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
376 		int doforce = xop->dopermanent & H2DOPERM_FORCE;
377 		uint8_t type;
378 
379 		/*
380 		 * If the directory entry is the actual inode then use its
381 		 * type for the directory typing tests, otherwise if it is
382 		 * a directory entry, pull the type field from the entry.
383 		 *
384 		 * Directory entries are always permanently deleted
385 		 * (because they aren't the actual inode).
386 		 */
387 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
388 			type = chain->bref.embed.dirent.type;
389 			dopermanent |= HAMMER2_DELETE_PERMANENT;
390 		} else {
391 			type = chain->data->ipdata.meta.type;
392 		}
393 
394 		/*
395 		 * Check directory typing and delete the entry.  Note that
396 		 * nlinks adjustments are made on the real inode by the
397 		 * frontend, not here.
398 		 *
399 		 * Unfortunately, checkdirempty() may have to unlock (parent).
400 		 * If it no longer matches chain->parent after re-locking,
401 		 * EAGAIN is returned.
402 		 */
403 		if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
404 			/*
405 			 * If doforce then execute the operation even if
406 			 * the directory is not empty or errored.  We
407 			 * ignore chain->error here, allowing an errored
408 			 * chain (aka directory entry) to still be deleted.
409 			 */
410 			error = hammer2_chain_delete(parent, chain,
411 					     xop->head.mtid, dopermanent);
412 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
413 		    xop->isdir == 0) {
414 			error = HAMMER2_ERROR_EISDIR;
415 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
416 			   (error = checkdirempty(parent, chain, clindex)) != 0) {
417 			/*
418 			 * error may be EAGAIN or ENOTEMPTY
419 			 */
420 			if (error == HAMMER2_ERROR_EAGAIN) {
421 				hammer2_chain_unlock(chain);
422 				hammer2_chain_drop(chain);
423 				hammer2_chain_unlock(parent);
424 				hammer2_chain_drop(parent);
425 				goto again;
426 			}
427 		} else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
428 			   xop->isdir >= 1) {
429 			error = HAMMER2_ERROR_ENOTDIR;
430 		} else {
431 			/*
432 			 * Delete the directory entry.  chain might also
433 			 * be a directly-embedded inode.
434 			 *
435 			 * Allow the deletion to proceed even if the chain
436 			 * is errored.  Give priority to error-on-delete over
437 			 * chain->error.
438 			 */
439 			error = hammer2_chain_delete(parent, chain,
440 						     xop->head.mtid,
441 						     dopermanent);
442 			if (error == 0)
443 				error = chain->error;
444 		}
445 	} else {
446 		if (chain && error == 0)
447 			error = chain->error;
448 	}
449 
450 	/*
451 	 * If chain is a directory entry we must resolve it.  We do not try
452 	 * to manipulate the contents as it might not be synchronized with
453 	 * the frontend hammer2_inode_t, nor do we try to lookup the
454 	 * frontend hammer2_inode_t here (we are the backend!).
455 	 */
456 	if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
457 	    (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
458 		int error2;
459 
460 		lhc = chain->bref.embed.dirent.inum;
461 
462 		error2 = hammer2_chain_inode_find(chain->pmp, lhc,
463 						  clindex, 0,
464 						  &parent, &chain);
465 		if (error2) {
466 			kprintf("xop_unlink: %016jx %p failed\n",
467 				lhc, chain);
468 			error2 = 0;	/* silently ignore */
469 		}
470 		if (error == 0)
471 			error = error2;
472 	}
473 
474 	/*
475 	 * Return the inode target for further action.  Typically used by
476 	 * hammer2_inode_unlink_finisher().
477 	 */
478 done:
479 	hammer2_xop_feed(&xop->head, chain, clindex, error);
480 	if (chain) {
481 		hammer2_chain_unlock(chain);
482 		hammer2_chain_drop(chain);
483 		chain = NULL;
484 	}
485 	if (parent) {
486 		hammer2_chain_unlock(parent);
487 		hammer2_chain_drop(parent);
488 		parent = NULL;
489 	}
490 }
491 
492 /*
493  * Backend for hammer2_vop_nrename()
494  *
495  * This handles the backend rename operation.  Typically this renames
496  * directory entries but can also be used to rename embedded inodes.
497  *
498  * NOTE! The frontend is responsible for updating the inode meta-data in
499  *	 the file being renamed and for decrementing the target-replaced
500  *	 inode's nlinks, if present.
501  */
502 void
503 hammer2_xop_nrename(hammer2_xop_t *arg, void *scratch, int clindex)
504 {
505 	hammer2_xop_nrename_t *xop = &arg->xop_nrename;
506 	hammer2_pfs_t *pmp;
507 	hammer2_chain_t *parent;
508 	hammer2_chain_t *chain;
509 	hammer2_chain_t *tmp;
510 	hammer2_inode_t *ip;
511 	hammer2_key_t key_next;
512 	int error;
513 
514 	/*
515 	 * If ip4 is non-NULL we must check to see if the entry being
516 	 * overwritten is a non-empty directory.
517 	 */
518 	ip = xop->head.ip4;
519 	if (ip) {
520 		uint8_t type;
521 
522 		chain = hammer2_inode_chain(ip, clindex,
523 					    HAMMER2_RESOLVE_ALWAYS);
524 		if (chain == NULL) {
525 			error = HAMMER2_ERROR_EIO;
526 			parent = NULL;
527 			goto done;
528 		}
529 		type = chain->data->ipdata.meta.type;
530 		if (type == HAMMER2_OBJTYPE_DIRECTORY &&
531 		    (error = checkdirempty(NULL, chain, clindex)) != 0)
532 		{
533 		    KKASSERT(error != HAMMER2_ERROR_EAGAIN);
534 		    parent = NULL;
535 		    goto done;
536 		}
537 		hammer2_chain_unlock(chain);
538 		hammer2_chain_drop(chain);
539 	}
540 
541 	/*
542 	 * We need the precise parent chain to issue the deletion.
543 	 *
544 	 * If this is a directory entry we must locate the underlying
545 	 * inode.  If it is an embedded inode we can act directly on it.
546 	 */
547 	ip = xop->head.ip2;
548 	pmp = ip->pmp;
549 	chain = NULL;
550 	error = 0;
551 
552 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
553 		/*
554 		 * Find ip's direct parent chain.
555 		 */
556 		chain = hammer2_inode_chain(ip, clindex,
557 					    HAMMER2_RESOLVE_ALWAYS);
558 		if (chain == NULL) {
559 			error = HAMMER2_ERROR_EIO;
560 			parent = NULL;
561 			goto done;
562 		}
563 		if (ip->flags & HAMMER2_INODE_CREATING) {
564 			parent = NULL;
565 		} else {
566 			parent = hammer2_chain_getparent(chain,
567 						    HAMMER2_RESOLVE_ALWAYS);
568 			if (parent == NULL) {
569 				error = HAMMER2_ERROR_EIO;
570 				goto done;
571 			}
572 		}
573 	} else {
574 		/*
575 		 * The directory entry for the head.ip1 inode
576 		 * is in fdip, do a namespace search.
577 		 */
578 		hammer2_key_t lhc;
579 		const char *name;
580 		size_t name_len;
581 
582 		parent = hammer2_inode_chain(xop->head.ip1, clindex,
583 					     HAMMER2_RESOLVE_ALWAYS);
584 		if (parent == NULL) {
585 			kprintf("xop_nrename: NULL parent\n");
586 			error = HAMMER2_ERROR_EIO;
587 			goto done;
588 		}
589 		name = xop->head.name1;
590 		name_len = xop->head.name1_len;
591 
592 		/*
593 		 * Lookup the directory entry
594 		 */
595 		lhc = hammer2_dirhash(name, name_len);
596 		chain = hammer2_chain_lookup(&parent, &key_next,
597 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
598 					     &error, HAMMER2_LOOKUP_ALWAYS);
599 		while (chain) {
600 			if (hammer2_chain_dirent_test(chain, name, name_len))
601 				break;
602 			chain = hammer2_chain_next(&parent, chain, &key_next,
603 						   key_next,
604 						   lhc + HAMMER2_DIRHASH_LOMASK,
605 						   &error,
606 						   HAMMER2_LOOKUP_ALWAYS);
607 		}
608 	}
609 
610 	if (chain == NULL) {
611 		/* XXX shouldn't happen, but does under fsstress */
612 		kprintf("xop_nrename: \"%s\" -> \"%s\"  ENOENT\n",
613 			xop->head.name1,
614 			xop->head.name2);
615 		if (error == 0)
616 			error = HAMMER2_ERROR_ENOENT;
617 		goto done;
618 	}
619 
620 	if (chain->error) {
621 		error = chain->error;
622 		goto done;
623 	}
624 
625 	/*
626 	 * Delete it, then create it in the new namespace.
627 	 *
628 	 * An error can occur if the chain being deleted requires
629 	 * modification and the media is full.
630 	 */
631 	error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
632 	if (parent) {
633 		hammer2_chain_unlock(parent);
634 		hammer2_chain_drop(parent);
635 		parent = NULL;		/* safety */
636 	} else {
637 		kprintf("hammer2_xop_nrename() (debugging): parent was NULL\n");
638 		error = EINVAL;
639 	}
640 	if (error)
641 		goto done;
642 
643 	/*
644 	 * Adjust fields in the deleted chain appropriate for the rename
645 	 * operation.
646 	 *
647 	 * NOTE! For embedded inodes, the frontend will officially replicate
648 	 *	 the field adjustments, but we also do it here to maintain
649 	 *	 consistency in case of a crash.
650 	 */
651 	if (chain->bref.key != xop->lhc ||
652 	    xop->head.name1_len != xop->head.name2_len ||
653 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
654 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
655 			hammer2_inode_data_t *wipdata;
656 
657 			error = hammer2_chain_modify(chain, xop->head.mtid,
658 						     0, 0);
659 			if (error == 0) {
660 				wipdata = &chain->data->ipdata;
661 
662 				bzero(wipdata->filename,
663 				      sizeof(wipdata->filename));
664 				bcopy(xop->head.name2,
665 				      wipdata->filename,
666 				      xop->head.name2_len);
667 				wipdata->meta.name_key = xop->lhc;
668 				wipdata->meta.name_len = xop->head.name2_len;
669 			}
670 		}
671 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
672 			if (xop->head.name2_len <=
673 			    sizeof(chain->bref.check.buf)) {
674 				/*
675 				 * Remove any related data buffer, we can
676 				 * embed the filename in the bref itself.
677 				 */
678 				error = hammer2_chain_resize(
679 						chain, xop->head.mtid, 0, 0, 0);
680 				if (error == 0) {
681 					error = hammer2_chain_modify(
682 							chain, xop->head.mtid,
683 							0, 0);
684 				}
685 				if (error == 0) {
686 					bzero(chain->bref.check.buf,
687 					      sizeof(chain->bref.check.buf));
688 					bcopy(xop->head.name2,
689 					      chain->bref.check.buf,
690 					      xop->head.name2_len);
691 				}
692 			} else {
693 				/*
694 				 * Associate a data buffer with the bref.
695 				 * Zero it for consistency.  Note that the
696 				 * data buffer is not 64KB so use chain->bytes
697 				 * instead of sizeof().
698 				 */
699 				error = hammer2_chain_resize(
700 					chain, xop->head.mtid, 0,
701 					hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
702 				if (error == 0) {
703 					error = hammer2_chain_modify(
704 						    chain, xop->head.mtid,
705 						    0, 0);
706 				}
707 				if (error == 0) {
708 					bzero(chain->data->buf, chain->bytes);
709 					bcopy(xop->head.name2,
710 					      chain->data->buf,
711 					      xop->head.name2_len);
712 				}
713 			}
714 			if (error == 0) {
715 				chain->bref.embed.dirent.namlen =
716 					xop->head.name2_len;
717 			}
718 		}
719 	}
720 
721 	/*
722 	 * The frontend will replicate this operation and is the real final
723 	 * authority, but adjust the inode's iparent field too if the inode
724 	 * is embedded in the directory.
725 	 */
726 	if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
727 	    chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
728 		hammer2_inode_data_t *wipdata;
729 
730 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
731 		if (error == 0) {
732 			wipdata = &chain->data->ipdata;
733 			wipdata->meta.iparent = xop->head.ip3->meta.inum;
734 		}
735 	}
736 
737 	/*
738 	 * Destroy any matching target(s) before creating the new entry.
739 	 * This will result in some ping-ponging of the directory key
740 	 * iterator but that is ok.
741 	 */
742 	parent = hammer2_inode_chain(xop->head.ip3, clindex,
743 				     HAMMER2_RESOLVE_ALWAYS);
744 	if (parent == NULL) {
745 		error = HAMMER2_ERROR_EIO;
746 		goto done;
747 	}
748 
749 	/*
750 	 * Delete all matching directory entries.  That is, get rid of
751 	 * multiple duplicates if present, as a self-healing mechanism.
752 	 */
753 	if (error == 0) {
754 		tmp = hammer2_chain_lookup(&parent, &key_next,
755 					   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
756 					   xop->lhc | HAMMER2_DIRHASH_LOMASK,
757 					   &error,
758 					   HAMMER2_LOOKUP_ALWAYS);
759 		while (tmp) {
760 			int e2;
761 			if (hammer2_chain_dirent_test(tmp, xop->head.name2,
762 						      xop->head.name2_len)) {
763 				e2 = hammer2_chain_delete(parent, tmp,
764 							  xop->head.mtid, 0);
765 				if (error == 0 && e2)
766 					error = e2;
767 			}
768 			tmp = hammer2_chain_next(&parent, tmp, &key_next,
769 						 key_next,
770 						 xop->lhc |
771 						  HAMMER2_DIRHASH_LOMASK,
772 						 &error,
773 						 HAMMER2_LOOKUP_ALWAYS);
774 		}
775 	}
776 	if (error == 0) {
777 		/*
778 		 * A relookup is required before the create to properly
779 		 * position the parent chain.
780 		 */
781 		tmp = hammer2_chain_lookup(&parent, &key_next,
782 					   xop->lhc, xop->lhc,
783 					   &error, 0);
784 		KKASSERT(tmp == NULL);
785 		error = hammer2_chain_create(&parent, &chain, NULL, pmp,
786 					     HAMMER2_METH_DEFAULT,
787 					     xop->lhc, 0,
788 					     HAMMER2_BREF_TYPE_INODE,
789 					     HAMMER2_INODE_BYTES,
790 					     xop->head.mtid, 0, 0);
791 	}
792 done:
793 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
794 	if (parent) {
795 		hammer2_chain_unlock(parent);
796 		hammer2_chain_drop(parent);
797 	}
798 	if (chain) {
799 		hammer2_chain_unlock(chain);
800 		hammer2_chain_drop(chain);
801 	}
802 }
803 
804 /*
805  * Directory collision resolver scan helper (backend, threaded).
806  *
807  * Used by the inode create code to locate an unused lhc.
808  */
809 void
810 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex)
811 {
812 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
813 	hammer2_chain_t *parent;
814 	hammer2_chain_t *chain;
815 	hammer2_key_t key_next;
816 	int error = 0;
817 
818 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
819 				     HAMMER2_RESOLVE_ALWAYS |
820 				     HAMMER2_RESOLVE_SHARED);
821 	if (parent == NULL) {
822 		kprintf("xop_scanlhc: NULL parent\n");
823 		chain = NULL;
824 		error = HAMMER2_ERROR_EIO;
825 		goto done;
826 	}
827 
828 	/*
829 	 * Lookup all possibly conflicting directory entries, the feed
830 	 * inherits the chain's lock so do not unlock it on the iteration.
831 	 */
832 	chain = hammer2_chain_lookup(&parent, &key_next,
833 				     xop->lhc,
834 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
835 				     &error,
836 				     HAMMER2_LOOKUP_ALWAYS |
837 				     HAMMER2_LOOKUP_SHARED);
838 	while (chain) {
839 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
840 		if (error) {
841 			hammer2_chain_unlock(chain);
842 			hammer2_chain_drop(chain);
843 			chain = NULL;	/* safety */
844 			goto done;
845 		}
846 		chain = hammer2_chain_next(&parent, chain, &key_next,
847 					   key_next,
848 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
849 					   &error,
850 					   HAMMER2_LOOKUP_ALWAYS |
851 					   HAMMER2_LOOKUP_SHARED);
852 	}
853 done:
854 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
855 	if (parent) {
856 		hammer2_chain_unlock(parent);
857 		hammer2_chain_drop(parent);
858 	}
859 }
860 
861 /*
862  * Generic lookup of a specific key.
863  */
864 void
865 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex)
866 {
867 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
868 	hammer2_chain_t *parent;
869 	hammer2_chain_t *chain;
870 	hammer2_key_t key_next;
871 	int error = 0;
872 
873 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
874 				     HAMMER2_RESOLVE_ALWAYS |
875 				     HAMMER2_RESOLVE_SHARED);
876 	chain = NULL;
877 	if (parent == NULL) {
878 		error = HAMMER2_ERROR_EIO;
879 		goto done;
880 	}
881 
882 	/*
883 	 * Lookup all possibly conflicting directory entries, the feed
884 	 * inherits the chain's lock so do not unlock it on the iteration.
885 	 */
886 	chain = hammer2_chain_lookup(&parent, &key_next,
887 				     xop->lhc, xop->lhc,
888 				     &error,
889 				     HAMMER2_LOOKUP_ALWAYS |
890 				     HAMMER2_LOOKUP_SHARED);
891 	if (error == 0) {
892 		if (chain)
893 			error = chain->error;
894 		else
895 			error = HAMMER2_ERROR_ENOENT;
896 	}
897 	hammer2_xop_feed(&xop->head, chain, clindex, error);
898 
899 done:
900 	if (chain) {
901 		hammer2_chain_unlock(chain);
902 		hammer2_chain_drop(chain);
903 	}
904 	if (parent) {
905 		hammer2_chain_unlock(parent);
906 		hammer2_chain_drop(parent);
907 	}
908 }
909 
910 void
911 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex)
912 {
913 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
914 	hammer2_chain_t *parent;
915 	hammer2_chain_t *chain;
916 	hammer2_key_t key_next;
917 	int error = 0;
918 
919 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
920 				     HAMMER2_RESOLVE_ALWAYS);
921 	chain = NULL;
922 	if (parent == NULL) {
923 		error = HAMMER2_ERROR_EIO;
924 		goto done;
925 	}
926 
927 	/*
928 	 * Lookup all possibly conflicting directory entries, the feed
929 	 * inherits the chain's lock so do not unlock it on the iteration.
930 	 */
931 	chain = hammer2_chain_lookup(&parent, &key_next,
932 				     xop->lhc, xop->lhc,
933 				     &error,
934 				     HAMMER2_LOOKUP_NODATA);
935 	if (error == 0) {
936 		if (chain)
937 			error = chain->error;
938 		else
939 			error = HAMMER2_ERROR_ENOENT;
940 	}
941 	if (chain) {
942 		error = hammer2_chain_delete(parent, chain, xop->head.mtid,
943 					     HAMMER2_DELETE_PERMANENT);
944 	}
945 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
946 
947 done:
948 	if (chain) {
949 		hammer2_chain_unlock(chain);
950 		hammer2_chain_drop(chain);
951 	}
952 	if (parent) {
953 		hammer2_chain_unlock(parent);
954 		hammer2_chain_drop(parent);
955 	}
956 }
957 
958 /*
959  * Generic scan
960  *
961  * WARNING! Fed chains must be locked shared so ownership can be transfered
962  *	    and to prevent frontend/backend stalls that would occur with an
963  *	    exclusive lock.  The shared lock also allows chain->data to be
964  *	    retained.
965  */
966 void
967 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex)
968 {
969 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
970 	hammer2_chain_t *parent;
971 	hammer2_chain_t *chain;
972 	hammer2_key_t key_next;
973 	int error = 0;
974 
975 	/*
976 	 * Assert required flags.
977 	 */
978 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
979 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
980 
981 	/*
982 	 * The inode's chain is the iterator.  If we cannot acquire it our
983 	 * contribution ends here.
984 	 */
985 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
986 				     xop->resolve_flags);
987 	if (parent == NULL) {
988 		kprintf("xop_scanall: NULL parent\n");
989 		goto done;
990 	}
991 
992 	/*
993 	 * Generic scan of exact records.  Note that indirect blocks are
994 	 * automatically recursed and will not be returned.
995 	 */
996 	chain = hammer2_chain_lookup(&parent, &key_next,
997 				     xop->key_beg, xop->key_end,
998 				     &error, xop->lookup_flags);
999 	while (chain) {
1000 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
1001 		if (error)
1002 			goto break2;
1003 		chain = hammer2_chain_next(&parent, chain, &key_next,
1004 					   key_next, xop->key_end,
1005 					   &error, xop->lookup_flags);
1006 	}
1007 break2:
1008 	if (chain) {
1009 		hammer2_chain_unlock(chain);
1010 		hammer2_chain_drop(chain);
1011 	}
1012 	hammer2_chain_unlock(parent);
1013 	hammer2_chain_drop(parent);
1014 done:
1015 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1016 }
1017 
1018 /************************************************************************
1019  *			    INODE LAYER XOPS				*
1020  ************************************************************************
1021  *
1022  */
1023 /*
1024  * Helper to create a directory entry.
1025  */
1026 void
1027 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex)
1028 {
1029 	hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent;
1030 	hammer2_chain_t *parent;
1031 	hammer2_chain_t *chain;
1032 	hammer2_key_t key_next;
1033 	size_t data_len;
1034 	int error;
1035 
1036 	if (hammer2_debug & 0x0001)
1037 		kprintf("xop_inode_mkdirent: lhc %016jx clindex %d\n",
1038 			xop->lhc, clindex);
1039 
1040 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1041 				     HAMMER2_RESOLVE_ALWAYS);
1042 	if (parent == NULL) {
1043 		error = HAMMER2_ERROR_EIO;
1044 		chain = NULL;
1045 		goto fail;
1046 	}
1047 	chain = hammer2_chain_lookup(&parent, &key_next,
1048 				     xop->lhc, xop->lhc,
1049 				     &error, 0);
1050 	if (chain) {
1051 		error = HAMMER2_ERROR_EEXIST;
1052 		goto fail;
1053 	}
1054 
1055 	/*
1056 	 * We may be able to embed the directory entry directly in the
1057 	 * blockref.
1058 	 */
1059 	if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1060 		data_len = 0;
1061 	else
1062 		data_len = HAMMER2_ALLOC_MIN;
1063 
1064 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1065 				     HAMMER2_METH_DEFAULT,
1066 				     xop->lhc, 0,
1067 				     HAMMER2_BREF_TYPE_DIRENT,
1068 				     data_len,
1069 				     xop->head.mtid, 0, 0);
1070 	if (error == 0) {
1071 		/*
1072 		 * WARNING: chain->data->buf is sized to chain->bytes,
1073 		 *	    do not use sizeof(chain->data->buf), which
1074 		 *	    will be much larger.
1075 		 */
1076 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1077 		if (error == 0) {
1078 			chain->bref.embed.dirent = xop->dirent;
1079 			if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1080 				bcopy(xop->head.name1, chain->bref.check.buf,
1081 				      xop->dirent.namlen);
1082 			else
1083 				bcopy(xop->head.name1, chain->data->buf,
1084 				      xop->dirent.namlen);
1085 		}
1086 	}
1087 fail:
1088 	if (parent) {
1089 		hammer2_chain_unlock(parent);
1090 		hammer2_chain_drop(parent);
1091 	}
1092 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1093 	if (chain) {
1094 		hammer2_chain_unlock(chain);
1095 		hammer2_chain_drop(chain);
1096 	}
1097 }
1098 
1099 /*
1100  * Inode create helper (threaded, backend)
1101  *
1102  * Used by ncreate, nmknod, nsymlink, nmkdir.
1103  * Used by nlink and rename to create HARDLINK pointers.
1104  *
1105  * Frontend holds the parent directory ip locked exclusively.  We
1106  * create the inode and feed the exclusively locked chain to the
1107  * frontend.
1108  */
1109 void
1110 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex)
1111 {
1112 	hammer2_xop_create_t *xop = &arg->xop_create;
1113 	hammer2_chain_t *parent;
1114 	hammer2_chain_t *chain;
1115 	hammer2_key_t key_next;
1116 	int error;
1117 
1118 	if (hammer2_debug & 0x0001)
1119 		kprintf("xop_inode_create: lhc %016jx clindex %d\n",
1120 			xop->lhc, clindex);
1121 
1122 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1123 				     HAMMER2_RESOLVE_ALWAYS);
1124 	if (parent == NULL) {
1125 		error = HAMMER2_ERROR_EIO;
1126 		chain = NULL;
1127 		goto fail;
1128 	}
1129 	chain = hammer2_chain_lookup(&parent, &key_next,
1130 				     xop->lhc, xop->lhc,
1131 				     &error, 0);
1132 	if (chain) {
1133 		error = HAMMER2_ERROR_EEXIST;
1134 		goto fail;
1135 	}
1136 
1137 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1138 				     HAMMER2_METH_DEFAULT,
1139 				     xop->lhc, 0,
1140 				     HAMMER2_BREF_TYPE_INODE,
1141 				     HAMMER2_INODE_BYTES,
1142 				     xop->head.mtid, 0, xop->flags);
1143 	if (error == 0) {
1144 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1145 		if (error == 0) {
1146 			chain->data->ipdata.meta = xop->meta;
1147 			if (xop->head.name1) {
1148 				bcopy(xop->head.name1,
1149 				      chain->data->ipdata.filename,
1150 				      xop->head.name1_len);
1151 				chain->data->ipdata.meta.name_len =
1152 					xop->head.name1_len;
1153 			}
1154 			chain->data->ipdata.meta.name_key = xop->lhc;
1155 		}
1156 	}
1157 fail:
1158 	if (parent) {
1159 		hammer2_chain_unlock(parent);
1160 		hammer2_chain_drop(parent);
1161 	}
1162 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1163 	if (chain) {
1164 		hammer2_chain_unlock(chain);
1165 		hammer2_chain_drop(chain);
1166 	}
1167 }
1168 
1169 /*
1170  * Create inode as above but leave it detached from the hierarchy.
1171  */
1172 void
1173 hammer2_xop_inode_create_det(hammer2_xop_t *arg, void *scratch, int clindex)
1174 {
1175 	hammer2_xop_create_t *xop = &arg->xop_create;
1176 	hammer2_chain_t *parent;
1177 	hammer2_chain_t *chain;
1178 	hammer2_chain_t *null_parent;
1179 	hammer2_key_t key_next;
1180 	hammer2_inode_t *pip;
1181 	hammer2_inode_t *iroot;
1182 	int error;
1183 
1184 	if (hammer2_debug & 0x0001)
1185 		kprintf("xop_inode_create_det: lhc %016jx clindex %d\n",
1186 			xop->lhc, clindex);
1187 
1188 	pip = xop->head.ip1;
1189 	iroot = pip->pmp->iroot;
1190 
1191 	parent = hammer2_inode_chain(iroot, clindex, HAMMER2_RESOLVE_ALWAYS);
1192 
1193 	if (parent == NULL) {
1194 		error = HAMMER2_ERROR_EIO;
1195 		chain = NULL;
1196 		goto fail;
1197 	}
1198 	chain = hammer2_chain_lookup(&parent, &key_next,
1199 				     xop->lhc, xop->lhc,
1200 				     &error, 0);
1201 	if (chain) {
1202 		error = HAMMER2_ERROR_EEXIST;
1203 		goto fail;
1204 	}
1205 
1206 	/*
1207 	 * Create as a detached chain with no parent.  We must specify
1208 	 * methods
1209 	 */
1210 	null_parent = NULL;
1211 	error = hammer2_chain_create(&null_parent, &chain,
1212 				     parent->hmp, pip->pmp,
1213 				     HAMMER2_ENC_COMP(pip->meta.comp_algo) +
1214 				     HAMMER2_ENC_CHECK(pip->meta.check_algo),
1215 				     xop->lhc, 0,
1216 				     HAMMER2_BREF_TYPE_INODE,
1217 				     HAMMER2_INODE_BYTES,
1218 				     xop->head.mtid, 0, xop->flags);
1219 	if (error == 0) {
1220 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1221 		if (error == 0) {
1222 			chain->data->ipdata.meta = xop->meta;
1223 			if (xop->head.name1) {
1224 				bcopy(xop->head.name1,
1225 				      chain->data->ipdata.filename,
1226 				      xop->head.name1_len);
1227 				chain->data->ipdata.meta.name_len =
1228 					xop->head.name1_len;
1229 			}
1230 			chain->data->ipdata.meta.name_key = xop->lhc;
1231 		}
1232 	}
1233 fail:
1234 	if (parent) {
1235 		hammer2_chain_unlock(parent);
1236 		hammer2_chain_drop(parent);
1237 	}
1238 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1239 	if (chain) {
1240 		hammer2_chain_unlock(chain);
1241 		hammer2_chain_drop(chain);
1242 	}
1243 }
1244 
1245 /*
1246  * Take a detached chain and insert it into the topology
1247  */
1248 void
1249 hammer2_xop_inode_create_ins(hammer2_xop_t *arg, void *scratch, int clindex)
1250 {
1251 	hammer2_xop_create_t *xop = &arg->xop_create;
1252 	hammer2_chain_t *parent;
1253 	hammer2_chain_t *chain;
1254 	hammer2_key_t key_next;
1255 	int error;
1256 
1257 	if (hammer2_debug & 0x0001)
1258 		kprintf("xop_inode_create_ins: lhc %016jx clindex %d\n",
1259 			xop->lhc, clindex);
1260 
1261 	/*
1262 	 * (parent) will be the insertion point for inode under iroot
1263 	 */
1264 	parent = hammer2_inode_chain(xop->head.ip1->pmp->iroot, clindex,
1265 				     HAMMER2_RESOLVE_ALWAYS);
1266 	if (parent == NULL) {
1267 		error = HAMMER2_ERROR_EIO;
1268 		chain = NULL;
1269 		goto fail;
1270 	}
1271 	chain = hammer2_chain_lookup(&parent, &key_next,
1272 				     xop->lhc, xop->lhc,
1273 				     &error, 0);
1274 	if (chain) {
1275 		error = HAMMER2_ERROR_EEXIST;
1276 		goto fail;
1277 	}
1278 
1279 	/*
1280 	 * (chain) is the detached inode that is being inserted
1281 	 */
1282 	chain = hammer2_inode_chain(xop->head.ip1, clindex,
1283 				     HAMMER2_RESOLVE_ALWAYS);
1284 	if (chain == NULL) {
1285 		error = HAMMER2_ERROR_EIO;
1286 		chain = NULL;
1287 		goto fail;
1288 	}
1289 
1290 	/*
1291 	 * This create call will insert the non-NULL chain into parent.
1292 	 * Most of the auxillary fields are ignored since the chain already
1293 	 * exists.
1294 	 */
1295 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1296 				     HAMMER2_METH_DEFAULT,
1297 				     xop->lhc, 0,
1298 				     HAMMER2_BREF_TYPE_INODE,
1299 				     HAMMER2_INODE_BYTES,
1300 				     xop->head.mtid, 0, xop->flags);
1301 #if 0
1302 	if (error == 0) {
1303 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1304 		if (error == 0) {
1305 			chain->data->ipdata.meta = xop->meta;
1306 			if (xop->head.name1) {
1307 				bcopy(xop->head.name1,
1308 				      chain->data->ipdata.filename,
1309 				      xop->head.name1_len);
1310 				chain->data->ipdata.meta.name_len =
1311 					xop->head.name1_len;
1312 			}
1313 			chain->data->ipdata.meta.name_key = xop->lhc;
1314 		}
1315 	}
1316 #endif
1317 fail:
1318 	if (parent) {
1319 		hammer2_chain_unlock(parent);
1320 		hammer2_chain_drop(parent);
1321 	}
1322 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1323 	if (chain) {
1324 		hammer2_chain_unlock(chain);
1325 		hammer2_chain_drop(chain);
1326 	}
1327 }
1328 
1329 /*
1330  * Inode delete helper (backend, threaded)
1331  *
1332  * Generally used by hammer2_run_sideq()
1333  */
1334 void
1335 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex)
1336 {
1337 	hammer2_xop_destroy_t *xop = &arg->xop_destroy;
1338 	hammer2_pfs_t *pmp;
1339 	hammer2_chain_t *parent;
1340 	hammer2_chain_t *chain;
1341 	hammer2_inode_t *ip;
1342 	int error;
1343 
1344 	/*
1345 	 * We need the precise parent chain to issue the deletion.
1346 	 */
1347 	ip = xop->head.ip1;
1348 	pmp = ip->pmp;
1349 
1350 	chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
1351 	if (chain == NULL) {
1352 		parent = NULL;
1353 		error = HAMMER2_ERROR_EIO;
1354 		goto done;
1355 	}
1356 
1357 	if (ip->flags & HAMMER2_INODE_CREATING) {
1358 		/*
1359 		 * Inode's chains are not linked into the media topology
1360 		 * because it is a new inode (which is now being destroyed).
1361 		 */
1362 		parent = NULL;
1363 	} else {
1364 		/*
1365 		 * Inode's chains are linked into the media topology
1366 		 */
1367 		parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
1368 		if (parent == NULL) {
1369 			error = HAMMER2_ERROR_EIO;
1370 			goto done;
1371 		}
1372 	}
1373 	KKASSERT(chain->parent == parent);
1374 
1375 	/*
1376 	 * We have the correct parent, we can issue the deletion.
1377 	 */
1378 	hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
1379 	error = 0;
1380 done:
1381 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1382 	if (parent) {
1383 		hammer2_chain_unlock(parent);
1384 		hammer2_chain_drop(parent);
1385 	}
1386 	if (chain) {
1387 		hammer2_chain_unlock(chain);
1388 		hammer2_chain_drop(chain);
1389 	}
1390 }
1391 
1392 void
1393 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex)
1394 {
1395 	hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall;
1396 	hammer2_chain_t *parent;
1397 	hammer2_chain_t *chain;
1398 	hammer2_key_t key_next;
1399 	int error;
1400 
1401 	/*
1402 	 * We need the precise parent chain to issue the deletion.
1403 	 */
1404 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1405 				     HAMMER2_RESOLVE_ALWAYS);
1406 	chain = NULL;
1407 	if (parent == NULL) {
1408 		error = 0;
1409 		goto done;
1410 	}
1411 	chain = hammer2_chain_lookup(&parent, &key_next,
1412 				     xop->key_beg, xop->key_end,
1413 				     &error, HAMMER2_LOOKUP_ALWAYS);
1414 	while (chain) {
1415 		hammer2_chain_delete(parent, chain,
1416 				     xop->head.mtid, HAMMER2_DELETE_PERMANENT);
1417 		hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
1418 		/* depend on function to unlock the shared lock */
1419 		chain = hammer2_chain_next(&parent, chain, &key_next,
1420 					   key_next, xop->key_end,
1421 					   &error,
1422 					   HAMMER2_LOOKUP_ALWAYS);
1423 	}
1424 done:
1425 	if (error == 0)
1426 		error = HAMMER2_ERROR_ENOENT;
1427 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1428 	if (parent) {
1429 		hammer2_chain_unlock(parent);
1430 		hammer2_chain_drop(parent);
1431 	}
1432 	if (chain) {
1433 		hammer2_chain_unlock(chain);
1434 		hammer2_chain_drop(chain);
1435 	}
1436 }
1437 
1438 void
1439 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex)
1440 {
1441 	hammer2_xop_connect_t *xop = &arg->xop_connect;
1442 	hammer2_inode_data_t *wipdata;
1443 	hammer2_chain_t *parent;
1444 	hammer2_chain_t *chain;
1445 	hammer2_pfs_t *pmp;
1446 	hammer2_key_t key_dummy;
1447 	int error;
1448 
1449 	/*
1450 	 * Get directory, then issue a lookup to prime the parent chain
1451 	 * for the create.  The lookup is expected to fail.
1452 	 */
1453 	pmp = xop->head.ip1->pmp;
1454 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1455 				     HAMMER2_RESOLVE_ALWAYS);
1456 	if (parent == NULL) {
1457 		chain = NULL;
1458 		error = HAMMER2_ERROR_EIO;
1459 		goto fail;
1460 	}
1461 	chain = hammer2_chain_lookup(&parent, &key_dummy,
1462 				     xop->lhc, xop->lhc,
1463 				     &error, 0);
1464 	if (chain) {
1465 		hammer2_chain_unlock(chain);
1466 		hammer2_chain_drop(chain);
1467 		chain = NULL;
1468 		error = HAMMER2_ERROR_EEXIST;
1469 		goto fail;
1470 	}
1471 	if (error)
1472 		goto fail;
1473 
1474 	/*
1475 	 * Adjust the filename in the inode, set the name key.
1476 	 *
1477 	 * NOTE: Frontend must also adjust ip2->meta on success, we can't
1478 	 *	 do it here.
1479 	 */
1480 	chain = hammer2_inode_chain(xop->head.ip2, clindex,
1481 				    HAMMER2_RESOLVE_ALWAYS);
1482 	error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1483 	if (error)
1484 		goto fail;
1485 
1486 	wipdata = &chain->data->ipdata;
1487 
1488 	hammer2_inode_modify(xop->head.ip2);
1489 	if (xop->head.name1) {
1490 		bzero(wipdata->filename, sizeof(wipdata->filename));
1491 		bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len);
1492 		wipdata->meta.name_len = xop->head.name1_len;
1493 	}
1494 	wipdata->meta.name_key = xop->lhc;
1495 
1496 	/*
1497 	 * Reconnect the chain to the new parent directory
1498 	 */
1499 	error = hammer2_chain_create(&parent, &chain, NULL, pmp,
1500 				     HAMMER2_METH_DEFAULT,
1501 				     xop->lhc, 0,
1502 				     HAMMER2_BREF_TYPE_INODE,
1503 				     HAMMER2_INODE_BYTES,
1504 				     xop->head.mtid, 0, 0);
1505 
1506 	/*
1507 	 * Feed result back.
1508 	 */
1509 fail:
1510 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1511 	if (parent) {
1512 		hammer2_chain_unlock(parent);
1513 		hammer2_chain_drop(parent);
1514 	}
1515 	if (chain) {
1516 		hammer2_chain_unlock(chain);
1517 		hammer2_chain_drop(chain);
1518 	}
1519 }
1520 
1521 /*
1522  * Synchronize the in-memory inode with the chain.  This does not flush
1523  * the chain to disk.  Instead, it makes front-end inode changes visible
1524  * in the chain topology, thus visible to the backend.  This is done in an
1525  * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled
1526  * manner inside the vfs_sync.
1527  */
1528 void
1529 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex)
1530 {
1531 	hammer2_xop_fsync_t *xop = &arg->xop_fsync;
1532 	hammer2_chain_t	*parent;
1533 	hammer2_chain_t	*chain;
1534 	int error;
1535 
1536 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1537 				     HAMMER2_RESOLVE_ALWAYS);
1538 	chain = NULL;
1539 	if (parent == NULL) {
1540 		error = HAMMER2_ERROR_EIO;
1541 		goto done;
1542 	}
1543 	if (parent->error) {
1544 		error = parent->error;
1545 		goto done;
1546 	}
1547 
1548 	error = 0;
1549 
1550 	if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) {
1551 		/* osize must be ignored */
1552 	} else if (xop->meta.size < xop->osize) {
1553 		/*
1554 		 * We must delete any chains beyond the EOF.  The chain
1555 		 * straddling the EOF will be pending in the bioq.
1556 		 */
1557 		hammer2_key_t lbase;
1558 		hammer2_key_t key_next;
1559 
1560 		lbase = (xop->meta.size + HAMMER2_PBUFMASK64) &
1561 			~HAMMER2_PBUFMASK64;
1562 		chain = hammer2_chain_lookup(&parent, &key_next,
1563 					     lbase, HAMMER2_KEY_MAX,
1564 					     &error,
1565 					     HAMMER2_LOOKUP_NODATA |
1566 					     HAMMER2_LOOKUP_NODIRECT);
1567 		while (chain) {
1568 			/*
1569 			 * Degenerate embedded case, nothing to loop on
1570 			 */
1571 			switch (chain->bref.type) {
1572 			case HAMMER2_BREF_TYPE_DIRENT:
1573 			case HAMMER2_BREF_TYPE_INODE:
1574 				KKASSERT(0);
1575 				break;
1576 			case HAMMER2_BREF_TYPE_DATA:
1577 				hammer2_chain_delete(parent, chain,
1578 						     xop->head.mtid,
1579 						     HAMMER2_DELETE_PERMANENT);
1580 				break;
1581 			}
1582 			chain = hammer2_chain_next(&parent, chain, &key_next,
1583 						   key_next, HAMMER2_KEY_MAX,
1584 						   &error,
1585 						   HAMMER2_LOOKUP_NODATA |
1586 						   HAMMER2_LOOKUP_NODIRECT);
1587 		}
1588 
1589 		/*
1590 		 * Reset to point at inode for following code, if necessary.
1591 		 */
1592 		if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) {
1593 			hammer2_chain_unlock(parent);
1594 			hammer2_chain_drop(parent);
1595 			parent = hammer2_inode_chain(xop->head.ip1,
1596 						     clindex,
1597 						     HAMMER2_RESOLVE_ALWAYS);
1598 			kprintf("xop_inode_chain_sync: TRUNCATE RESET on '%s'\n",
1599 				parent->data->ipdata.filename);
1600 		}
1601 	}
1602 
1603 	/*
1604 	 * Sync the inode meta-data, potentially clear the blockset area
1605 	 * of direct data so it can be used for blockrefs.
1606 	 */
1607 	if (error == 0) {
1608 		error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0);
1609 		if (error == 0) {
1610 			parent->data->ipdata.meta = xop->meta;
1611 			if (xop->clear_directdata) {
1612 				bzero(&parent->data->ipdata.u.blockset,
1613 				      sizeof(parent->data->ipdata.u.blockset));
1614 			}
1615 		}
1616 	}
1617 done:
1618 	if (chain) {
1619 		hammer2_chain_unlock(chain);
1620 		hammer2_chain_drop(chain);
1621 	}
1622 	if (parent) {
1623 		hammer2_chain_unlock(parent);
1624 		hammer2_chain_drop(parent);
1625 	}
1626 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1627 }
1628