xref: /dragonfly/sys/vfs/hammer2/hammer2_xops.c (revision 8af44722)
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 	 * We need the precise parent chain to issue the deletion.
526 	 *
527 	 * If this is a directory entry we must locate the underlying
528 	 * inode.  If it is an embedded inode we can act directly on it.
529 	 */
530 	ip = xop->head.ip2;
531 	pmp = ip->pmp;
532 	chain = NULL;
533 	error = 0;
534 
535 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
536 		/*
537 		 * Find ip's direct parent chain.
538 		 */
539 		chain = hammer2_inode_chain(ip, clindex,
540 					    HAMMER2_RESOLVE_ALWAYS);
541 		if (chain == NULL) {
542 			error = HAMMER2_ERROR_EIO;
543 			parent = NULL;
544 			goto done;
545 		}
546 		if (ip->flags & HAMMER2_INODE_CREATING) {
547 			parent = NULL;
548 		} else {
549 			parent = hammer2_chain_getparent(chain,
550 						    HAMMER2_RESOLVE_ALWAYS);
551 			if (parent == NULL) {
552 				error = HAMMER2_ERROR_EIO;
553 				goto done;
554 			}
555 		}
556 	} else {
557 		/*
558 		 * The directory entry for the head.ip1 inode
559 		 * is in fdip, do a namespace search.
560 		 */
561 		hammer2_key_t lhc;
562 		const char *name;
563 		size_t name_len;
564 
565 		parent = hammer2_inode_chain(xop->head.ip1, clindex,
566 					     HAMMER2_RESOLVE_ALWAYS);
567 		if (parent == NULL) {
568 			kprintf("xop_nrename: NULL parent\n");
569 			error = HAMMER2_ERROR_EIO;
570 			goto done;
571 		}
572 		name = xop->head.name1;
573 		name_len = xop->head.name1_len;
574 
575 		/*
576 		 * Lookup the directory entry
577 		 */
578 		lhc = hammer2_dirhash(name, name_len);
579 		chain = hammer2_chain_lookup(&parent, &key_next,
580 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
581 					     &error, HAMMER2_LOOKUP_ALWAYS);
582 		while (chain) {
583 			if (hammer2_chain_dirent_test(chain, name, name_len))
584 				break;
585 			chain = hammer2_chain_next(&parent, chain, &key_next,
586 						   key_next,
587 						   lhc + HAMMER2_DIRHASH_LOMASK,
588 						   &error,
589 						   HAMMER2_LOOKUP_ALWAYS);
590 		}
591 	}
592 
593 	if (chain == NULL) {
594 		/* XXX shouldn't happen, but does under fsstress */
595 		kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
596 			xop->head.name1,
597 			xop->head.name2);
598 		if (error == 0)
599 			error = HAMMER2_ERROR_ENOENT;
600 		goto done;
601 	}
602 
603 	if (chain->error) {
604 		error = chain->error;
605 		goto done;
606 	}
607 
608 	/*
609 	 * Delete it, then create it in the new namespace.
610 	 *
611 	 * An error can occur if the chain being deleted requires
612 	 * modification and the media is full.
613 	 */
614 	error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
615 	hammer2_chain_unlock(parent);
616 	hammer2_chain_drop(parent);
617 	parent = NULL;		/* safety */
618 	if (error)
619 		goto done;
620 
621 	/*
622 	 * Adjust fields in the deleted chain appropriate for the rename
623 	 * operation.
624 	 *
625 	 * NOTE! For embedded inodes, the frontend will officially replicate
626 	 *	 the field adjustments, but we also do it here to maintain
627 	 *	 consistency in case of a crash.
628 	 */
629 	if (chain->bref.key != xop->lhc ||
630 	    xop->head.name1_len != xop->head.name2_len ||
631 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
632 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
633 			hammer2_inode_data_t *wipdata;
634 
635 			error = hammer2_chain_modify(chain, xop->head.mtid,
636 						     0, 0);
637 			if (error == 0) {
638 				wipdata = &chain->data->ipdata;
639 
640 				bzero(wipdata->filename,
641 				      sizeof(wipdata->filename));
642 				bcopy(xop->head.name2,
643 				      wipdata->filename,
644 				      xop->head.name2_len);
645 				wipdata->meta.name_key = xop->lhc;
646 				wipdata->meta.name_len = xop->head.name2_len;
647 			}
648 		}
649 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
650 			if (xop->head.name2_len <=
651 			    sizeof(chain->bref.check.buf)) {
652 				/*
653 				 * Remove any related data buffer, we can
654 				 * embed the filename in the bref itself.
655 				 */
656 				error = hammer2_chain_resize(
657 						chain, xop->head.mtid, 0, 0, 0);
658 				if (error == 0) {
659 					error = hammer2_chain_modify(
660 							chain, xop->head.mtid,
661 							0, 0);
662 				}
663 				if (error == 0) {
664 					bzero(chain->bref.check.buf,
665 					      sizeof(chain->bref.check.buf));
666 					bcopy(xop->head.name2,
667 					      chain->bref.check.buf,
668 					      xop->head.name2_len);
669 				}
670 			} else {
671 				/*
672 				 * Associate a data buffer with the bref.
673 				 * Zero it for consistency.  Note that the
674 				 * data buffer is not 64KB so use chain->bytes
675 				 * instead of sizeof().
676 				 */
677 				error = hammer2_chain_resize(
678 					chain, xop->head.mtid, 0,
679 					hammer2_getradix(HAMMER2_ALLOC_MIN), 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->data->buf, chain->bytes);
687 					bcopy(xop->head.name2,
688 					      chain->data->buf,
689 					      xop->head.name2_len);
690 				}
691 			}
692 			if (error == 0) {
693 				chain->bref.embed.dirent.namlen =
694 					xop->head.name2_len;
695 			}
696 		}
697 	}
698 
699 	/*
700 	 * The frontend will replicate this operation and is the real final
701 	 * authority, but adjust the inode's iparent field too if the inode
702 	 * is embedded in the directory.
703 	 */
704 	if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
705 	    chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
706 		hammer2_inode_data_t *wipdata;
707 
708 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
709 		if (error == 0) {
710 			wipdata = &chain->data->ipdata;
711 			wipdata->meta.iparent = xop->head.ip3->meta.inum;
712 		}
713 	}
714 
715 	/*
716 	 * Destroy any matching target(s) before creating the new entry.
717 	 * This will result in some ping-ponging of the directory key
718 	 * iterator but that is ok.
719 	 */
720 	parent = hammer2_inode_chain(xop->head.ip3, clindex,
721 				     HAMMER2_RESOLVE_ALWAYS);
722 	if (parent == NULL) {
723 		error = HAMMER2_ERROR_EIO;
724 		goto done;
725 	}
726 
727 	/*
728 	 * Delete all matching directory entries.  That is, get rid of
729 	 * multiple duplicates if present, as a self-healing mechanism.
730 	 */
731 	if (error == 0) {
732 		tmp = hammer2_chain_lookup(&parent, &key_next,
733 					   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
734 					   xop->lhc | HAMMER2_DIRHASH_LOMASK,
735 					   &error,
736 					   HAMMER2_LOOKUP_ALWAYS);
737 		while (tmp) {
738 			int e2;
739 			if (hammer2_chain_dirent_test(tmp, xop->head.name2,
740 						      xop->head.name2_len)) {
741 				e2 = hammer2_chain_delete(parent, tmp,
742 							  xop->head.mtid, 0);
743 				if (error == 0 && e2)
744 					error = e2;
745 			}
746 			tmp = hammer2_chain_next(&parent, tmp, &key_next,
747 						 key_next,
748 						 xop->lhc |
749 						  HAMMER2_DIRHASH_LOMASK,
750 						 &error,
751 						 HAMMER2_LOOKUP_ALWAYS);
752 		}
753 	}
754 	if (error == 0) {
755 		/*
756 		 * A relookup is required before the create to properly
757 		 * position the parent chain.
758 		 */
759 		tmp = hammer2_chain_lookup(&parent, &key_next,
760 					   xop->lhc, xop->lhc,
761 					   &error, 0);
762 		KKASSERT(tmp == NULL);
763 		error = hammer2_chain_create(&parent, &chain, NULL, pmp,
764 					     HAMMER2_METH_DEFAULT,
765 					     xop->lhc, 0,
766 					     HAMMER2_BREF_TYPE_INODE,
767 					     HAMMER2_INODE_BYTES,
768 					     xop->head.mtid, 0, 0);
769 	}
770 done:
771 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
772 	if (parent) {
773 		hammer2_chain_unlock(parent);
774 		hammer2_chain_drop(parent);
775 	}
776 	if (chain) {
777 		hammer2_chain_unlock(chain);
778 		hammer2_chain_drop(chain);
779 	}
780 }
781 
782 /*
783  * Directory collision resolver scan helper (backend, threaded).
784  *
785  * Used by the inode create code to locate an unused lhc.
786  */
787 void
788 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex)
789 {
790 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
791 	hammer2_chain_t *parent;
792 	hammer2_chain_t *chain;
793 	hammer2_key_t key_next;
794 	int error = 0;
795 
796 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
797 				     HAMMER2_RESOLVE_ALWAYS |
798 				     HAMMER2_RESOLVE_SHARED);
799 	if (parent == NULL) {
800 		kprintf("xop_nresolve: NULL parent\n");
801 		chain = NULL;
802 		error = HAMMER2_ERROR_EIO;
803 		goto done;
804 	}
805 
806 	/*
807 	 * Lookup all possibly conflicting directory entries, the feed
808 	 * inherits the chain's lock so do not unlock it on the iteration.
809 	 */
810 	chain = hammer2_chain_lookup(&parent, &key_next,
811 				     xop->lhc,
812 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
813 				     &error,
814 				     HAMMER2_LOOKUP_ALWAYS |
815 				     HAMMER2_LOOKUP_SHARED);
816 	while (chain) {
817 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
818 		if (error) {
819 			hammer2_chain_unlock(chain);
820 			hammer2_chain_drop(chain);
821 			chain = NULL;	/* safety */
822 			goto done;
823 		}
824 		chain = hammer2_chain_next(&parent, chain, &key_next,
825 					   key_next,
826 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
827 					   &error,
828 					   HAMMER2_LOOKUP_ALWAYS |
829 					   HAMMER2_LOOKUP_SHARED);
830 	}
831 done:
832 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
833 	if (parent) {
834 		hammer2_chain_unlock(parent);
835 		hammer2_chain_drop(parent);
836 	}
837 }
838 
839 /*
840  * Generic lookup of a specific key.
841  */
842 void
843 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex)
844 {
845 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
846 	hammer2_chain_t *parent;
847 	hammer2_chain_t *chain;
848 	hammer2_key_t key_next;
849 	int error = 0;
850 
851 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
852 				     HAMMER2_RESOLVE_ALWAYS |
853 				     HAMMER2_RESOLVE_SHARED);
854 	chain = NULL;
855 	if (parent == NULL) {
856 		error = HAMMER2_ERROR_EIO;
857 		goto done;
858 	}
859 
860 	/*
861 	 * Lookup all possibly conflicting directory entries, the feed
862 	 * inherits the chain's lock so do not unlock it on the iteration.
863 	 */
864 	chain = hammer2_chain_lookup(&parent, &key_next,
865 				     xop->lhc, xop->lhc,
866 				     &error,
867 				     HAMMER2_LOOKUP_ALWAYS |
868 				     HAMMER2_LOOKUP_SHARED);
869 	if (error == 0) {
870 		if (chain)
871 			error = chain->error;
872 		else
873 			error = HAMMER2_ERROR_ENOENT;
874 	}
875 	hammer2_xop_feed(&xop->head, chain, clindex, error);
876 
877 done:
878 	if (chain) {
879 		hammer2_chain_unlock(chain);
880 		hammer2_chain_drop(chain);
881 	}
882 	if (parent) {
883 		hammer2_chain_unlock(parent);
884 		hammer2_chain_drop(parent);
885 	}
886 }
887 
888 void
889 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex)
890 {
891 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
892 	hammer2_chain_t *parent;
893 	hammer2_chain_t *chain;
894 	hammer2_key_t key_next;
895 	int error = 0;
896 
897 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
898 				     HAMMER2_RESOLVE_ALWAYS);
899 	chain = NULL;
900 	if (parent == NULL) {
901 		error = HAMMER2_ERROR_EIO;
902 		goto done;
903 	}
904 
905 	/*
906 	 * Lookup all possibly conflicting directory entries, the feed
907 	 * inherits the chain's lock so do not unlock it on the iteration.
908 	 */
909 	chain = hammer2_chain_lookup(&parent, &key_next,
910 				     xop->lhc, xop->lhc,
911 				     &error,
912 				     HAMMER2_LOOKUP_NODATA);
913 	if (error == 0) {
914 		if (chain)
915 			error = chain->error;
916 		else
917 			error = HAMMER2_ERROR_ENOENT;
918 	}
919 	if (chain) {
920 		error = hammer2_chain_delete(parent, chain, xop->head.mtid,
921 					     HAMMER2_DELETE_PERMANENT);
922 	}
923 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
924 
925 done:
926 	if (chain) {
927 		hammer2_chain_unlock(chain);
928 		hammer2_chain_drop(chain);
929 	}
930 	if (parent) {
931 		hammer2_chain_unlock(parent);
932 		hammer2_chain_drop(parent);
933 	}
934 }
935 
936 /*
937  * Generic scan
938  *
939  * WARNING! Fed chains must be locked shared so ownership can be transfered
940  *	    and to prevent frontend/backend stalls that would occur with an
941  *	    exclusive lock.  The shared lock also allows chain->data to be
942  *	    retained.
943  */
944 void
945 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex)
946 {
947 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
948 	hammer2_chain_t *parent;
949 	hammer2_chain_t *chain;
950 	hammer2_key_t key_next;
951 	int error = 0;
952 
953 	/*
954 	 * Assert required flags.
955 	 */
956 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
957 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
958 
959 	/*
960 	 * The inode's chain is the iterator.  If we cannot acquire it our
961 	 * contribution ends here.
962 	 */
963 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
964 				     xop->resolve_flags);
965 	if (parent == NULL) {
966 		kprintf("xop_readdir: NULL parent\n");
967 		goto done;
968 	}
969 
970 	/*
971 	 * Generic scan of exact records.  Note that indirect blocks are
972 	 * automatically recursed and will not be returned.
973 	 */
974 	chain = hammer2_chain_lookup(&parent, &key_next,
975 				     xop->key_beg, xop->key_end,
976 				     &error, xop->lookup_flags);
977 	while (chain) {
978 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
979 		if (error)
980 			goto break2;
981 		chain = hammer2_chain_next(&parent, chain, &key_next,
982 					   key_next, xop->key_end,
983 					   &error, xop->lookup_flags);
984 	}
985 break2:
986 	if (chain) {
987 		hammer2_chain_unlock(chain);
988 		hammer2_chain_drop(chain);
989 	}
990 	hammer2_chain_unlock(parent);
991 	hammer2_chain_drop(parent);
992 done:
993 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
994 }
995 
996 /************************************************************************
997  *			    INODE LAYER XOPS				*
998  ************************************************************************
999  *
1000  */
1001 /*
1002  * Helper to create a directory entry.
1003  */
1004 void
1005 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex)
1006 {
1007 	hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent;
1008 	hammer2_chain_t *parent;
1009 	hammer2_chain_t *chain;
1010 	hammer2_key_t key_next;
1011 	size_t data_len;
1012 	int error;
1013 
1014 	if (hammer2_debug & 0x0001)
1015 		kprintf("dirent_create lhc %016jx clindex %d\n",
1016 			xop->lhc, clindex);
1017 
1018 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1019 				     HAMMER2_RESOLVE_ALWAYS);
1020 	if (parent == NULL) {
1021 		error = HAMMER2_ERROR_EIO;
1022 		chain = NULL;
1023 		goto fail;
1024 	}
1025 	chain = hammer2_chain_lookup(&parent, &key_next,
1026 				     xop->lhc, xop->lhc,
1027 				     &error, 0);
1028 	if (chain) {
1029 		error = HAMMER2_ERROR_EEXIST;
1030 		goto fail;
1031 	}
1032 
1033 	/*
1034 	 * We may be able to embed the directory entry directly in the
1035 	 * blockref.
1036 	 */
1037 	if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1038 		data_len = 0;
1039 	else
1040 		data_len = HAMMER2_ALLOC_MIN;
1041 
1042 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1043 				     HAMMER2_METH_DEFAULT,
1044 				     xop->lhc, 0,
1045 				     HAMMER2_BREF_TYPE_DIRENT,
1046 				     data_len,
1047 				     xop->head.mtid, 0, 0);
1048 	if (error == 0) {
1049 		/*
1050 		 * WARNING: chain->data->buf is sized to chain->bytes,
1051 		 *	    do not use sizeof(chain->data->buf), which
1052 		 *	    will be much larger.
1053 		 */
1054 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1055 		if (error == 0) {
1056 			chain->bref.embed.dirent = xop->dirent;
1057 			if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1058 				bcopy(xop->head.name1, chain->bref.check.buf,
1059 				      xop->dirent.namlen);
1060 			else
1061 				bcopy(xop->head.name1, chain->data->buf,
1062 				      xop->dirent.namlen);
1063 		}
1064 	}
1065 fail:
1066 	if (parent) {
1067 		hammer2_chain_unlock(parent);
1068 		hammer2_chain_drop(parent);
1069 	}
1070 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1071 	if (chain) {
1072 		hammer2_chain_unlock(chain);
1073 		hammer2_chain_drop(chain);
1074 	}
1075 }
1076 
1077 /*
1078  * Inode create helper (threaded, backend)
1079  *
1080  * Used by ncreate, nmknod, nsymlink, nmkdir.
1081  * Used by nlink and rename to create HARDLINK pointers.
1082  *
1083  * Frontend holds the parent directory ip locked exclusively.  We
1084  * create the inode and feed the exclusively locked chain to the
1085  * frontend.
1086  */
1087 void
1088 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex)
1089 {
1090 	hammer2_xop_create_t *xop = &arg->xop_create;
1091 	hammer2_chain_t *parent;
1092 	hammer2_chain_t *chain;
1093 	hammer2_key_t key_next;
1094 	int error;
1095 
1096 	if (hammer2_debug & 0x0001)
1097 		kprintf("inode_create lhc %016jx clindex %d\n",
1098 			xop->lhc, clindex);
1099 
1100 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1101 				     HAMMER2_RESOLVE_ALWAYS);
1102 	if (parent == NULL) {
1103 		error = HAMMER2_ERROR_EIO;
1104 		chain = NULL;
1105 		goto fail;
1106 	}
1107 	chain = hammer2_chain_lookup(&parent, &key_next,
1108 				     xop->lhc, xop->lhc,
1109 				     &error, 0);
1110 	if (chain) {
1111 		error = HAMMER2_ERROR_EEXIST;
1112 		goto fail;
1113 	}
1114 
1115 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1116 				     HAMMER2_METH_DEFAULT,
1117 				     xop->lhc, 0,
1118 				     HAMMER2_BREF_TYPE_INODE,
1119 				     HAMMER2_INODE_BYTES,
1120 				     xop->head.mtid, 0, xop->flags);
1121 	if (error == 0) {
1122 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1123 		if (error == 0) {
1124 			chain->data->ipdata.meta = xop->meta;
1125 			if (xop->head.name1) {
1126 				bcopy(xop->head.name1,
1127 				      chain->data->ipdata.filename,
1128 				      xop->head.name1_len);
1129 				chain->data->ipdata.meta.name_len =
1130 					xop->head.name1_len;
1131 			}
1132 			chain->data->ipdata.meta.name_key = xop->lhc;
1133 		}
1134 	}
1135 fail:
1136 	if (parent) {
1137 		hammer2_chain_unlock(parent);
1138 		hammer2_chain_drop(parent);
1139 	}
1140 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1141 	if (chain) {
1142 		hammer2_chain_unlock(chain);
1143 		hammer2_chain_drop(chain);
1144 	}
1145 }
1146 
1147 /*
1148  * Create inode as above but leave it detached from the hierarchy.
1149  */
1150 void
1151 hammer2_xop_inode_create_det(hammer2_xop_t *arg, void *scratch, int clindex)
1152 {
1153 	hammer2_xop_create_t *xop = &arg->xop_create;
1154 	hammer2_chain_t *parent;
1155 	hammer2_chain_t *chain;
1156 	hammer2_chain_t *null_parent;
1157 	hammer2_key_t key_next;
1158 	hammer2_inode_t *pip;
1159 	hammer2_inode_t *iroot;
1160 	int error;
1161 
1162 	if (hammer2_debug & 0x0001)
1163 		kprintf("inode_create_det lhc %016jx clindex %d\n",
1164 			xop->lhc, clindex);
1165 
1166 	pip = xop->head.ip1;
1167 	iroot = pip->pmp->iroot;
1168 
1169 	parent = hammer2_inode_chain(iroot, clindex, HAMMER2_RESOLVE_ALWAYS);
1170 
1171 	if (parent == NULL) {
1172 		error = HAMMER2_ERROR_EIO;
1173 		chain = NULL;
1174 		goto fail;
1175 	}
1176 	chain = hammer2_chain_lookup(&parent, &key_next,
1177 				     xop->lhc, xop->lhc,
1178 				     &error, 0);
1179 	if (chain) {
1180 		error = HAMMER2_ERROR_EEXIST;
1181 		goto fail;
1182 	}
1183 
1184 	/*
1185 	 * Create as a detached chain with no parent.  We must specify
1186 	 * methods
1187 	 */
1188 	null_parent = NULL;
1189 	error = hammer2_chain_create(&null_parent, &chain,
1190 				     parent->hmp, pip->pmp,
1191 				     HAMMER2_ENC_COMP(pip->meta.comp_algo) +
1192 				     HAMMER2_ENC_CHECK(pip->meta.check_algo),
1193 				     xop->lhc, 0,
1194 				     HAMMER2_BREF_TYPE_INODE,
1195 				     HAMMER2_INODE_BYTES,
1196 				     xop->head.mtid, 0, xop->flags);
1197 	if (error == 0) {
1198 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1199 		if (error == 0) {
1200 			chain->data->ipdata.meta = xop->meta;
1201 			if (xop->head.name1) {
1202 				bcopy(xop->head.name1,
1203 				      chain->data->ipdata.filename,
1204 				      xop->head.name1_len);
1205 				chain->data->ipdata.meta.name_len =
1206 					xop->head.name1_len;
1207 			}
1208 			chain->data->ipdata.meta.name_key = xop->lhc;
1209 		}
1210 	}
1211 fail:
1212 	if (parent) {
1213 		hammer2_chain_unlock(parent);
1214 		hammer2_chain_drop(parent);
1215 	}
1216 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1217 	if (chain) {
1218 		hammer2_chain_unlock(chain);
1219 		hammer2_chain_drop(chain);
1220 	}
1221 }
1222 
1223 /*
1224  * Take a detached chain and insert it into the topology
1225  */
1226 void
1227 hammer2_xop_inode_create_ins(hammer2_xop_t *arg, void *scratch, int clindex)
1228 {
1229 	hammer2_xop_create_t *xop = &arg->xop_create;
1230 	hammer2_chain_t *parent;
1231 	hammer2_chain_t *chain;
1232 	hammer2_key_t key_next;
1233 	int error;
1234 
1235 	if (hammer2_debug & 0x0001)
1236 		kprintf("inode_create_ins lhc %016jx clindex %d\n",
1237 			xop->lhc, clindex);
1238 
1239 	/*
1240 	 * (parent) will be the insertion point for inode under iroot
1241 	 */
1242 	parent = hammer2_inode_chain(xop->head.ip1->pmp->iroot, clindex,
1243 				     HAMMER2_RESOLVE_ALWAYS);
1244 	if (parent == NULL) {
1245 		error = HAMMER2_ERROR_EIO;
1246 		chain = NULL;
1247 		goto fail;
1248 	}
1249 	chain = hammer2_chain_lookup(&parent, &key_next,
1250 				     xop->lhc, xop->lhc,
1251 				     &error, 0);
1252 	if (chain) {
1253 		error = HAMMER2_ERROR_EEXIST;
1254 		goto fail;
1255 	}
1256 
1257 	/*
1258 	 * (chain) is the detached inode that is being inserted
1259 	 */
1260 	chain = hammer2_inode_chain(xop->head.ip1, clindex,
1261 				     HAMMER2_RESOLVE_ALWAYS);
1262 	if (chain == NULL) {
1263 		error = HAMMER2_ERROR_EIO;
1264 		chain = NULL;
1265 		goto fail;
1266 	}
1267 
1268 	/*
1269 	 * This create call will insert the non-NULL chain into parent.
1270 	 * Most of the auxillary fields are ignored since the chain already
1271 	 * exists.
1272 	 */
1273 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1274 				     HAMMER2_METH_DEFAULT,
1275 				     xop->lhc, 0,
1276 				     HAMMER2_BREF_TYPE_INODE,
1277 				     HAMMER2_INODE_BYTES,
1278 				     xop->head.mtid, 0, xop->flags);
1279 #if 0
1280 	if (error == 0) {
1281 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1282 		if (error == 0) {
1283 			chain->data->ipdata.meta = xop->meta;
1284 			if (xop->head.name1) {
1285 				bcopy(xop->head.name1,
1286 				      chain->data->ipdata.filename,
1287 				      xop->head.name1_len);
1288 				chain->data->ipdata.meta.name_len =
1289 					xop->head.name1_len;
1290 			}
1291 			chain->data->ipdata.meta.name_key = xop->lhc;
1292 		}
1293 	}
1294 #endif
1295 fail:
1296 	if (parent) {
1297 		hammer2_chain_unlock(parent);
1298 		hammer2_chain_drop(parent);
1299 	}
1300 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1301 	if (chain) {
1302 		hammer2_chain_unlock(chain);
1303 		hammer2_chain_drop(chain);
1304 	}
1305 }
1306 
1307 /*
1308  * Inode delete helper (backend, threaded)
1309  *
1310  * Generally used by hammer2_run_sideq()
1311  */
1312 void
1313 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex)
1314 {
1315 	hammer2_xop_destroy_t *xop = &arg->xop_destroy;
1316 	hammer2_pfs_t *pmp;
1317 	hammer2_chain_t *parent;
1318 	hammer2_chain_t *chain;
1319 	hammer2_inode_t *ip;
1320 	int error;
1321 
1322 	/*
1323 	 * We need the precise parent chain to issue the deletion.
1324 	 */
1325 	ip = xop->head.ip1;
1326 	pmp = ip->pmp;
1327 
1328 	chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
1329 	if (chain == NULL) {
1330 		parent = NULL;
1331 		error = HAMMER2_ERROR_EIO;
1332 		goto done;
1333 	}
1334 
1335 	if (ip->flags & HAMMER2_INODE_CREATING) {
1336 		/*
1337 		 * Inode's chains are not linked into the media topology
1338 		 * because it is a new inode (which is now being destroyed).
1339 		 */
1340 		parent = NULL;
1341 	} else {
1342 		/*
1343 		 * Inode's chains are linked into the media topology
1344 		 */
1345 		parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
1346 		if (parent == NULL) {
1347 			error = HAMMER2_ERROR_EIO;
1348 			goto done;
1349 		}
1350 	}
1351 	KKASSERT(chain->parent == parent);
1352 
1353 	/*
1354 	 * We have the correct parent, we can issue the deletion.
1355 	 */
1356 	hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
1357 	error = 0;
1358 done:
1359 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1360 	if (parent) {
1361 		hammer2_chain_unlock(parent);
1362 		hammer2_chain_drop(parent);
1363 	}
1364 	if (chain) {
1365 		hammer2_chain_unlock(chain);
1366 		hammer2_chain_drop(chain);
1367 	}
1368 }
1369 
1370 void
1371 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex)
1372 {
1373 	hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall;
1374 	hammer2_chain_t *parent;
1375 	hammer2_chain_t *chain;
1376 	hammer2_key_t key_next;
1377 	int error;
1378 
1379 	/*
1380 	 * We need the precise parent chain to issue the deletion.
1381 	 */
1382 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1383 				     HAMMER2_RESOLVE_ALWAYS);
1384 	chain = NULL;
1385 	if (parent == NULL) {
1386 		error = 0;
1387 		goto done;
1388 	}
1389 	chain = hammer2_chain_lookup(&parent, &key_next,
1390 				     xop->key_beg, xop->key_end,
1391 				     &error, HAMMER2_LOOKUP_ALWAYS);
1392 	while (chain) {
1393 		hammer2_chain_delete(parent, chain,
1394 				     xop->head.mtid, HAMMER2_DELETE_PERMANENT);
1395 		hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
1396 		/* depend on function to unlock the shared lock */
1397 		chain = hammer2_chain_next(&parent, chain, &key_next,
1398 					   key_next, xop->key_end,
1399 					   &error,
1400 					   HAMMER2_LOOKUP_ALWAYS);
1401 	}
1402 done:
1403 	if (error == 0)
1404 		error = HAMMER2_ERROR_ENOENT;
1405 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1406 	if (parent) {
1407 		hammer2_chain_unlock(parent);
1408 		hammer2_chain_drop(parent);
1409 	}
1410 	if (chain) {
1411 		hammer2_chain_unlock(chain);
1412 		hammer2_chain_drop(chain);
1413 	}
1414 }
1415 
1416 void
1417 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex)
1418 {
1419 	hammer2_xop_connect_t *xop = &arg->xop_connect;
1420 	hammer2_inode_data_t *wipdata;
1421 	hammer2_chain_t *parent;
1422 	hammer2_chain_t *chain;
1423 	hammer2_pfs_t *pmp;
1424 	hammer2_key_t key_dummy;
1425 	int error;
1426 
1427 	/*
1428 	 * Get directory, then issue a lookup to prime the parent chain
1429 	 * for the create.  The lookup is expected to fail.
1430 	 */
1431 	pmp = xop->head.ip1->pmp;
1432 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1433 				     HAMMER2_RESOLVE_ALWAYS);
1434 	if (parent == NULL) {
1435 		chain = NULL;
1436 		error = HAMMER2_ERROR_EIO;
1437 		goto fail;
1438 	}
1439 	chain = hammer2_chain_lookup(&parent, &key_dummy,
1440 				     xop->lhc, xop->lhc,
1441 				     &error, 0);
1442 	if (chain) {
1443 		hammer2_chain_unlock(chain);
1444 		hammer2_chain_drop(chain);
1445 		chain = NULL;
1446 		error = HAMMER2_ERROR_EEXIST;
1447 		goto fail;
1448 	}
1449 	if (error)
1450 		goto fail;
1451 
1452 	/*
1453 	 * Adjust the filename in the inode, set the name key.
1454 	 *
1455 	 * NOTE: Frontend must also adjust ip2->meta on success, we can't
1456 	 *	 do it here.
1457 	 */
1458 	chain = hammer2_inode_chain(xop->head.ip2, clindex,
1459 				    HAMMER2_RESOLVE_ALWAYS);
1460 	error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1461 	if (error)
1462 		goto fail;
1463 
1464 	wipdata = &chain->data->ipdata;
1465 
1466 	hammer2_inode_modify(xop->head.ip2);
1467 	if (xop->head.name1) {
1468 		bzero(wipdata->filename, sizeof(wipdata->filename));
1469 		bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len);
1470 		wipdata->meta.name_len = xop->head.name1_len;
1471 	}
1472 	wipdata->meta.name_key = xop->lhc;
1473 
1474 	/*
1475 	 * Reconnect the chain to the new parent directory
1476 	 */
1477 	error = hammer2_chain_create(&parent, &chain, NULL, pmp,
1478 				     HAMMER2_METH_DEFAULT,
1479 				     xop->lhc, 0,
1480 				     HAMMER2_BREF_TYPE_INODE,
1481 				     HAMMER2_INODE_BYTES,
1482 				     xop->head.mtid, 0, 0);
1483 
1484 	/*
1485 	 * Feed result back.
1486 	 */
1487 fail:
1488 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1489 	if (parent) {
1490 		hammer2_chain_unlock(parent);
1491 		hammer2_chain_drop(parent);
1492 	}
1493 	if (chain) {
1494 		hammer2_chain_unlock(chain);
1495 		hammer2_chain_drop(chain);
1496 	}
1497 }
1498 
1499 /*
1500  * Synchronize the in-memory inode with the chain.  This does not flush
1501  * the chain to disk.  Instead, it makes front-end inode changes visible
1502  * in the chain topology, thus visible to the backend.  This is done in an
1503  * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled
1504  * manner inside the vfs_sync.
1505  */
1506 void
1507 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex)
1508 {
1509 	hammer2_xop_fsync_t *xop = &arg->xop_fsync;
1510 	hammer2_chain_t	*parent;
1511 	hammer2_chain_t	*chain;
1512 	int error;
1513 
1514 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1515 				     HAMMER2_RESOLVE_ALWAYS);
1516 	chain = NULL;
1517 	if (parent == NULL) {
1518 		error = HAMMER2_ERROR_EIO;
1519 		goto done;
1520 	}
1521 	if (parent->error) {
1522 		error = parent->error;
1523 		goto done;
1524 	}
1525 
1526 	error = 0;
1527 
1528 	if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) {
1529 		/* osize must be ignored */
1530 	} else if (xop->meta.size < xop->osize) {
1531 		/*
1532 		 * We must delete any chains beyond the EOF.  The chain
1533 		 * straddling the EOF will be pending in the bioq.
1534 		 */
1535 		hammer2_key_t lbase;
1536 		hammer2_key_t key_next;
1537 
1538 		lbase = (xop->meta.size + HAMMER2_PBUFMASK64) &
1539 			~HAMMER2_PBUFMASK64;
1540 		chain = hammer2_chain_lookup(&parent, &key_next,
1541 					     lbase, HAMMER2_KEY_MAX,
1542 					     &error,
1543 					     HAMMER2_LOOKUP_NODATA |
1544 					     HAMMER2_LOOKUP_NODIRECT);
1545 		while (chain) {
1546 			/*
1547 			 * Degenerate embedded case, nothing to loop on
1548 			 */
1549 			switch (chain->bref.type) {
1550 			case HAMMER2_BREF_TYPE_DIRENT:
1551 			case HAMMER2_BREF_TYPE_INODE:
1552 				KKASSERT(0);
1553 				break;
1554 			case HAMMER2_BREF_TYPE_DATA:
1555 				hammer2_chain_delete(parent, chain,
1556 						     xop->head.mtid,
1557 						     HAMMER2_DELETE_PERMANENT);
1558 				break;
1559 			}
1560 			chain = hammer2_chain_next(&parent, chain, &key_next,
1561 						   key_next, HAMMER2_KEY_MAX,
1562 						   &error,
1563 						   HAMMER2_LOOKUP_NODATA |
1564 						   HAMMER2_LOOKUP_NODIRECT);
1565 		}
1566 
1567 		/*
1568 		 * Reset to point at inode for following code, if necessary.
1569 		 */
1570 		if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) {
1571 			hammer2_chain_unlock(parent);
1572 			hammer2_chain_drop(parent);
1573 			parent = hammer2_inode_chain(xop->head.ip1,
1574 						     clindex,
1575 						     HAMMER2_RESOLVE_ALWAYS);
1576 			kprintf("hammer2: TRUNCATE RESET on '%s'\n",
1577 				parent->data->ipdata.filename);
1578 		}
1579 	}
1580 
1581 	/*
1582 	 * Sync the inode meta-data, potentially clear the blockset area
1583 	 * of direct data so it can be used for blockrefs.
1584 	 */
1585 	if (error == 0) {
1586 		error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0);
1587 		if (error == 0) {
1588 			parent->data->ipdata.meta = xop->meta;
1589 			if (xop->clear_directdata) {
1590 				bzero(&parent->data->ipdata.u.blockset,
1591 				      sizeof(parent->data->ipdata.u.blockset));
1592 			}
1593 		}
1594 	}
1595 done:
1596 	if (chain) {
1597 		hammer2_chain_unlock(chain);
1598 		hammer2_chain_drop(chain);
1599 	}
1600 	if (parent) {
1601 		hammer2_chain_unlock(parent);
1602 		hammer2_chain_drop(parent);
1603 	}
1604 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1605 }
1606