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