xref: /dragonfly/sys/vfs/hammer2/hammer2_xops.c (revision 6700dd34)
1 /*
2  * Copyright (c) 2011-2015 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/namei.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/mountctl.h>
54 #include <sys/dirent.h>
55 #include <sys/uio.h>
56 #include <sys/objcache.h>
57 #include <sys/event.h>
58 #include <sys/file.h>
59 #include <vfs/fifofs/fifo.h>
60 
61 #include "hammer2.h"
62 
63 /*
64  * Determine if the specified directory is empty.  Returns 0 on success.
65  */
66 static
67 int
68 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
69 {
70 	hammer2_chain_t *parent;
71 	hammer2_chain_t *chain;
72 	hammer2_key_t key_next;
73 	hammer2_key_t inum;
74 	int error;
75 
76 	error = 0;
77 	chain = hammer2_chain_lookup_init(ochain, 0);
78 
79 	if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
80 		if (oparent)
81 			hammer2_chain_unlock(oparent);
82 		inum = chain->bref.embed.dirent.inum;
83 		parent = NULL;
84 		error = hammer2_chain_inode_find(chain->pmp, inum,
85 						 clindex, 0,
86 						 &parent, &chain);
87 		if (parent) {
88 			hammer2_chain_unlock(parent);
89 			hammer2_chain_drop(parent);
90 		}
91 		if (oparent) {
92 			hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
93 			if (ochain->parent != oparent) {
94 				if (chain) {
95 					hammer2_chain_unlock(chain);
96 					hammer2_chain_drop(chain);
97 				}
98 				return HAMMER2_ERROR_EAGAIN;
99 			}
100 		}
101 	}
102 
103 	/*
104 	 * Determine if the directory is empty or not by checking its
105 	 * visible namespace (the area which contains directory entries).
106 	 */
107 	parent = chain;
108 	chain = NULL;
109 	if (parent) {
110 		chain = hammer2_chain_lookup(&parent, &key_next,
111 					     HAMMER2_DIRHASH_VISIBLE,
112 					     HAMMER2_KEY_MAX,
113 					     &error, 0);
114 	}
115 	if (chain) {
116 		error = HAMMER2_ERROR_ENOTEMPTY;
117 		hammer2_chain_unlock(chain);
118 		hammer2_chain_drop(chain);
119 	}
120 	hammer2_chain_lookup_done(parent);
121 
122 	return error;
123 }
124 
125 /*
126  * Backend for hammer2_vfs_root()
127  *
128  * This is called when a newly mounted PFS has not yet synchronized
129  * to the inode_tid and modify_tid.
130  */
131 void
132 hammer2_xop_ipcluster(hammer2_thread_t *thr, hammer2_xop_t *arg)
133 {
134 	hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
135 	hammer2_chain_t *chain;
136 	int error;
137 
138 	chain = hammer2_inode_chain(xop->head.ip1, thr->clindex,
139 				    HAMMER2_RESOLVE_ALWAYS |
140 				    HAMMER2_RESOLVE_SHARED);
141 	if (chain)
142 		error = chain->error;
143 	else
144 		error = HAMMER2_ERROR_EIO;
145 
146 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
147 	if (chain) {
148 		hammer2_chain_unlock(chain);
149 		hammer2_chain_drop(chain);
150 	}
151 }
152 
153 /*
154  * Backend for hammer2_vop_readdir()
155  */
156 void
157 hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg)
158 {
159 	hammer2_xop_readdir_t *xop = &arg->xop_readdir;
160 	hammer2_chain_t *parent;
161 	hammer2_chain_t *chain;
162 	hammer2_key_t key_next;
163 	hammer2_key_t lkey;
164 	int error = 0;
165 
166 	lkey = xop->lkey;
167 	if (hammer2_debug & 0x0020)
168 		kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
169 
170 	/*
171 	 * The inode's chain is the iterator.  If we cannot acquire it our
172 	 * contribution ends here.
173 	 */
174 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
175 				     HAMMER2_RESOLVE_ALWAYS |
176 				     HAMMER2_RESOLVE_SHARED);
177 	if (parent == NULL) {
178 		kprintf("xop_readdir: NULL parent\n");
179 		goto done;
180 	}
181 
182 	/*
183 	 * Directory scan [re]start and loop, the feed inherits the chain's
184 	 * lock so do not unlock it on the iteration.
185 	 */
186 	chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
187 				     &error, HAMMER2_LOOKUP_SHARED);
188 	if (chain == NULL) {
189 		chain = hammer2_chain_lookup(&parent, &key_next,
190 					     lkey, HAMMER2_KEY_MAX,
191 					     &error, HAMMER2_LOOKUP_SHARED);
192 	}
193 	while (chain) {
194 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
195 		if (error)
196 			goto break2;
197 		chain = hammer2_chain_next(&parent, chain, &key_next,
198 					   key_next, HAMMER2_KEY_MAX,
199 					   &error, HAMMER2_LOOKUP_SHARED);
200 	}
201 break2:
202 	if (chain) {
203 		hammer2_chain_unlock(chain);
204 		hammer2_chain_drop(chain);
205 	}
206 	hammer2_chain_unlock(parent);
207 	hammer2_chain_drop(parent);
208 done:
209 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
210 }
211 
212 /*
213  * Backend for hammer2_vop_nresolve()
214  */
215 void
216 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
217 {
218 	hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
219 	hammer2_chain_t *parent;
220 	hammer2_chain_t *chain;
221 	const char *name;
222 	size_t name_len;
223 	hammer2_key_t key_next;
224 	hammer2_key_t lhc;
225 	int error;
226 
227 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
228 				     HAMMER2_RESOLVE_ALWAYS |
229 				     HAMMER2_RESOLVE_SHARED);
230 	if (parent == NULL) {
231 		kprintf("xop_nresolve: NULL parent\n");
232 		chain = NULL;
233 		error = HAMMER2_ERROR_EIO;
234 		goto done;
235 	}
236 	name = xop->head.name1;
237 	name_len = xop->head.name1_len;
238 
239 	/*
240 	 * Lookup the directory entry
241 	 */
242 	lhc = hammer2_dirhash(name, name_len);
243 	chain = hammer2_chain_lookup(&parent, &key_next,
244 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
245 				     &error,
246 				     HAMMER2_LOOKUP_ALWAYS |
247 				     HAMMER2_LOOKUP_SHARED);
248 	while (chain) {
249 		if (hammer2_chain_dirent_test(chain, name, name_len))
250 			break;
251 		chain = hammer2_chain_next(&parent, chain, &key_next,
252 					   key_next,
253 					   lhc + HAMMER2_DIRHASH_LOMASK,
254 					   &error,
255 					   HAMMER2_LOOKUP_ALWAYS |
256 					   HAMMER2_LOOKUP_SHARED);
257 	}
258 
259 	/*
260 	 * If the entry is a hardlink pointer, resolve it.
261 	 */
262 	if (chain && chain->error == 0) {
263 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
264 			lhc = chain->bref.embed.dirent.inum;
265 			error = hammer2_chain_inode_find(chain->pmp,
266 							 lhc,
267 							 thr->clindex,
268 							 HAMMER2_LOOKUP_SHARED,
269 							 &parent,
270 							 &chain);
271 		}
272 	} else if (chain && error == 0) {
273 		error = chain->error;
274 	}
275 done:
276 	error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
277 	if (chain) {
278 		hammer2_chain_unlock(chain);
279 		hammer2_chain_drop(chain);
280 	}
281 	if (parent) {
282 		hammer2_chain_unlock(parent);
283 		hammer2_chain_drop(parent);
284 	}
285 }
286 
287 /*
288  * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
289  * backend for pfs_delete.
290  *
291  * This function locates and removes a directory entry, and will lookup
292  * and return the underlying inode.  For directory entries the underlying
293  * inode is not removed.  If the directory entry is the actual inode itself,
294  * it may be conditonally removed and returned.
295  *
296  * WARNING!  Any target inode's nlinks may not be synchronized to the
297  *	     in-memory inode.  The frontend's hammer2_inode_unlink_finisher()
298  *	     is responsible for the final disposition of the actual inode.
299  */
300 void
301 hammer2_xop_unlink(hammer2_thread_t *thr, hammer2_xop_t *arg)
302 {
303 	hammer2_xop_unlink_t *xop = &arg->xop_unlink;
304 	hammer2_chain_t *parent;
305 	hammer2_chain_t *chain;
306 	const char *name;
307 	size_t name_len;
308 	hammer2_key_t key_next;
309 	hammer2_key_t lhc;
310 	int error;
311 
312 again:
313 	/*
314 	 * Requires exclusive lock
315 	 */
316 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
317 				     HAMMER2_RESOLVE_ALWAYS);
318 	chain = NULL;
319 	if (parent == NULL) {
320 		kprintf("xop_nresolve: NULL parent\n");
321 		error = HAMMER2_ERROR_EIO;
322 		goto done;
323 	}
324 	name = xop->head.name1;
325 	name_len = xop->head.name1_len;
326 
327 	/*
328 	 * Lookup the directory entry
329 	 */
330 	lhc = hammer2_dirhash(name, name_len);
331 	chain = hammer2_chain_lookup(&parent, &key_next,
332 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
333 				     &error, HAMMER2_LOOKUP_ALWAYS);
334 	while (chain) {
335 		if (hammer2_chain_dirent_test(chain, name, name_len))
336 			break;
337 		chain = hammer2_chain_next(&parent, chain, &key_next,
338 					   key_next,
339 					   lhc + HAMMER2_DIRHASH_LOMASK,
340 					   &error, HAMMER2_LOOKUP_ALWAYS);
341 	}
342 
343 	/*
344 	 * The directory entry will either be a BREF_TYPE_DIRENT or a
345 	 * BREF_TYPE_INODE.  We always permanently delete DIRENTs, but
346 	 * must go by xop->dopermanent for BREF_TYPE_INODE.
347 	 *
348 	 * Note that the target chain's nlinks may not be synchronized with
349 	 * the in-memory hammer2_inode_t structure, so we don't try to do
350 	 * anything fancy here.  The frontend deals with nlinks
351 	 * synchronization.
352 	 */
353 	if (chain && chain->error == 0) {
354 		int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
355 		int doforce = xop->dopermanent & H2DOPERM_FORCE;
356 		uint8_t type;
357 
358 		/*
359 		 * If the directory entry is the actual inode then use its
360 		 * type for the directory typing tests, otherwise if it is
361 		 * a directory entry, pull the type field from the entry.
362 		 *
363 		 * Directory entries are always permanently deleted
364 		 * (because they aren't the actual inode).
365 		 */
366 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
367 			type = chain->bref.embed.dirent.type;
368 			dopermanent |= HAMMER2_DELETE_PERMANENT;
369 		} else {
370 			type = chain->data->ipdata.meta.type;
371 		}
372 
373 		/*
374 		 * Check directory typing and delete the entry.  Note that
375 		 * nlinks adjustments are made on the real inode by the
376 		 * frontend, not here.
377 		 *
378 		 * Unfortunately, checkdirempty() may have to unlock (parent).
379 		 * If it no longer matches chain->parent after re-locking,
380 		 * EAGAIN is returned.
381 		 */
382 		if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
383 			/*
384 			 * If doforce then execute the operation even if
385 			 * the directory is not empty or errored.
386 			 */
387 			/* ignore chain->error */
388 			error = hammer2_chain_delete(parent, chain,
389 					     xop->head.mtid, dopermanent);
390 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
391 			   (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
392 			/*
393 			 * error may be EAGAIN or ENOTEMPTY
394 			 */
395 			if (error == HAMMER2_ERROR_EAGAIN) {
396 				hammer2_chain_unlock(chain);
397 				hammer2_chain_drop(chain);
398 				hammer2_chain_unlock(parent);
399 				hammer2_chain_drop(parent);
400 				goto again;
401 			}
402 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
403 		    xop->isdir == 0) {
404 			error = HAMMER2_ERROR_ENOTDIR;
405 		} else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
406 			   xop->isdir >= 1) {
407 			error = HAMMER2_ERROR_EISDIR;
408 		} else {
409 			/*
410 			 * Delete the directory entry.  chain might also
411 			 * be a directly-embedded inode.
412 			 */
413 			error = chain->error;
414 			hammer2_chain_delete(parent, chain,
415 					     xop->head.mtid, dopermanent);
416 		}
417 	} else {
418 		if (chain && error == 0)
419 			error = chain->error;
420 	}
421 
422 	/*
423 	 * If chain is a directory entry we must resolve it.  We do not try
424 	 * to manipulate the contents as it might not be synchronized with
425 	 * the frontend hammer2_inode_t, nor do we try to lookup the
426 	 * frontend hammer2_inode_t here (we are the backend!).
427 	 */
428 	if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
429 	    (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
430 		int error2;
431 
432 		lhc = chain->bref.embed.dirent.inum;
433 
434 		error2 = hammer2_chain_inode_find(chain->pmp, lhc,
435 						  thr->clindex, 0,
436 						  &parent, &chain);
437 		if (error2) {
438 			kprintf("inode_find: %016jx %p failed\n",
439 				lhc, chain);
440 			error2 = 0;	/* silently ignore */
441 		}
442 		if (error == 0)
443 			error = error2;
444 	}
445 
446 	/*
447 	 * Return the inode target for further action.  Typically used by
448 	 * hammer2_inode_unlink_finisher().
449 	 */
450 done:
451 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
452 	if (chain) {
453 		hammer2_chain_unlock(chain);
454 		hammer2_chain_drop(chain);
455 		chain = NULL;
456 	}
457 	if (parent) {
458 		hammer2_chain_unlock(parent);
459 		hammer2_chain_drop(parent);
460 		parent = NULL;
461 	}
462 }
463 
464 /*
465  * Backend for hammer2_vop_nrename()
466  *
467  * This handles the backend rename operation.  Typically this renames
468  * directory entries but can also be used to rename embedded inodes.
469  *
470  * NOTE! The frontend is responsible for updating the inode meta-data in
471  *	 the file being renamed and for decrementing the target-replaced
472  *	 inode's nlinks, if present.
473  */
474 void
475 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
476 {
477 	hammer2_xop_nrename_t *xop = &arg->xop_nrename;
478 	hammer2_pfs_t *pmp;
479 	hammer2_chain_t *parent;
480 	hammer2_chain_t *chain;
481 	hammer2_chain_t *tmp;
482 	hammer2_inode_t *ip;
483 	hammer2_key_t key_next;
484 	int error;
485 
486 	/*
487 	 * We need the precise parent chain to issue the deletion.
488 	 *
489 	 * If this is a directory entry we must locate the underlying
490 	 * inode.  If it is an embedded inode we can act directly on it.
491 	 */
492 	ip = xop->head.ip2;
493 	pmp = ip->pmp;
494 	chain = NULL;
495 	error = 0;
496 
497 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
498 		/*
499 		 * Find ip's direct parent chain.
500 		 */
501 		chain = hammer2_inode_chain(ip, thr->clindex,
502 					    HAMMER2_RESOLVE_ALWAYS);
503 		if (chain == NULL) {
504 			error = HAMMER2_ERROR_EIO;
505 			parent = NULL;
506 			goto done;
507 		}
508 		parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
509 		if (parent == NULL) {
510 			error = HAMMER2_ERROR_EIO;
511 			goto done;
512 		}
513 	} else {
514 		/*
515 		 * The directory entry for the head.ip1 inode
516 		 * is in fdip, do a namespace search.
517 		 */
518 		hammer2_key_t lhc;
519 		const char *name;
520 		size_t name_len;
521 
522 		parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
523 					     HAMMER2_RESOLVE_ALWAYS);
524 		if (parent == NULL) {
525 			kprintf("xop_nrename: NULL parent\n");
526 			error = HAMMER2_ERROR_EIO;
527 			goto done;
528 		}
529 		name = xop->head.name1;
530 		name_len = xop->head.name1_len;
531 
532 		/*
533 		 * Lookup the directory entry
534 		 */
535 		lhc = hammer2_dirhash(name, name_len);
536 		chain = hammer2_chain_lookup(&parent, &key_next,
537 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
538 					     &error, HAMMER2_LOOKUP_ALWAYS);
539 		while (chain) {
540 			if (hammer2_chain_dirent_test(chain, name, name_len))
541 				break;
542 			chain = hammer2_chain_next(&parent, chain, &key_next,
543 						   key_next,
544 						   lhc + HAMMER2_DIRHASH_LOMASK,
545 						   &error,
546 						   HAMMER2_LOOKUP_ALWAYS);
547 		}
548 	}
549 
550 	if (chain == NULL) {
551 		/* XXX shouldn't happen, but does under fsstress */
552 		kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
553 			xop->head.name1,
554 			xop->head.name2);
555 		if (error == 0)
556 			error = HAMMER2_ERROR_ENOENT;
557 		goto done;
558 	}
559 
560 	if (chain->error) {
561 		error = chain->error;
562 		goto done;
563 	}
564 
565 	/*
566 	 * Delete it, then create it in the new namespace.
567 	 */
568 	hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
569 	hammer2_chain_unlock(parent);
570 	hammer2_chain_drop(parent);
571 	parent = NULL;		/* safety */
572 
573 	/*
574 	 * Adjust fields in the deleted chain appropriate for the rename
575 	 * operation.
576 	 *
577 	 * NOTE! For embedded inodes, the frontend will officially replicate
578 	 *	 the field adjustments, but we also do it here to maintain
579 	 *	 consistency in case of a crash.
580 	 */
581 	if (chain->bref.key != xop->lhc ||
582 	    xop->head.name1_len != xop->head.name2_len ||
583 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
584 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
585 			hammer2_inode_data_t *wipdata;
586 
587 			error = hammer2_chain_modify(chain, xop->head.mtid,
588 						     0, 0);
589 			if (error == 0) {
590 				wipdata = &chain->data->ipdata;
591 
592 				bzero(wipdata->filename,
593 				      sizeof(wipdata->filename));
594 				bcopy(xop->head.name2,
595 				      wipdata->filename,
596 				      xop->head.name2_len);
597 				wipdata->meta.name_key = xop->lhc;
598 				wipdata->meta.name_len = xop->head.name2_len;
599 			}
600 		}
601 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
602 			if (xop->head.name2_len <=
603 			    sizeof(chain->bref.check.buf)) {
604 				/*
605 				 * Remove any related data buffer, we can
606 				 * embed the filename in the bref itself.
607 				 */
608 				error = hammer2_chain_resize(
609 						chain, xop->head.mtid, 0, 0, 0);
610 				if (error == 0) {
611 					error = hammer2_chain_modify(
612 							chain, xop->head.mtid,
613 							0, 0);
614 				}
615 				if (error == 0) {
616 					bzero(chain->bref.check.buf,
617 					      sizeof(chain->bref.check.buf));
618 					bcopy(xop->head.name2,
619 					      chain->bref.check.buf,
620 					      xop->head.name2_len);
621 				}
622 			} else {
623 				/*
624 				 * Associate a data buffer with the bref.
625 				 * Zero it for consistency.  Note that the
626 				 * data buffer is not 64KB so use chain->bytes
627 				 * instead of sizeof().
628 				 */
629 				error = hammer2_chain_resize(
630 					chain, xop->head.mtid, 0,
631 					hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
632 				if (error == 0) {
633 					error = hammer2_chain_modify(
634 						    chain, xop->head.mtid,
635 						    0, 0);
636 				}
637 				if (error == 0) {
638 					bzero(chain->data->buf, chain->bytes);
639 					bcopy(xop->head.name2,
640 					      chain->data->buf,
641 					      xop->head.name2_len);
642 				}
643 			}
644 			if (error == 0) {
645 				chain->bref.embed.dirent.namlen =
646 					xop->head.name2_len;
647 			}
648 		}
649 	}
650 
651 	/*
652 	 * The frontend will replicate this operation and is the real final
653 	 * authority, but adjust the inode's iparent field too if the inode
654 	 * is embedded in the directory.
655 	 */
656 	if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
657 	    chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
658 		hammer2_inode_data_t *wipdata;
659 
660 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
661 		if (error == 0) {
662 			wipdata = &chain->data->ipdata;
663 			wipdata->meta.iparent = xop->head.ip3->meta.inum;
664 		}
665 	}
666 
667 	/*
668 	 * Destroy any matching target(s) before creating the new entry.
669 	 * This will result in some ping-ponging of the directory key
670 	 * iterator but that is ok.
671 	 */
672 	parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
673 				     HAMMER2_RESOLVE_ALWAYS);
674 	if (parent == NULL) {
675 		error = HAMMER2_ERROR_EIO;
676 		goto done;
677 	}
678 
679 	if (error == 0) {
680 		tmp = hammer2_chain_lookup(&parent, &key_next,
681 					   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
682 					   xop->lhc | HAMMER2_DIRHASH_LOMASK,
683 					   &error,
684 					   HAMMER2_LOOKUP_ALWAYS);
685 		while (tmp) {
686 			if (hammer2_chain_dirent_test(tmp, xop->head.name2,
687 						      xop->head.name2_len)) {
688 				hammer2_chain_delete(parent, tmp,
689 						     xop->head.mtid, 0);
690 			}
691 			tmp = hammer2_chain_next(&parent, tmp, &key_next,
692 						 key_next,
693 						 xop->lhc |
694 						  HAMMER2_DIRHASH_LOMASK,
695 						 &error,
696 						 HAMMER2_LOOKUP_ALWAYS);
697 		}
698 	}
699 	if (error == 0) {
700 		/*
701 		 * A relookup is required before the create to properly
702 		 * position the parent chain.
703 		 */
704 		tmp = hammer2_chain_lookup(&parent, &key_next,
705 					   xop->lhc, xop->lhc,
706 					   &error, 0);
707 		KKASSERT(tmp == NULL);
708 		error = hammer2_chain_create(&parent, &chain,
709 					     pmp, HAMMER2_METH_DEFAULT,
710 					     xop->lhc, 0,
711 					     HAMMER2_BREF_TYPE_INODE,
712 					     HAMMER2_INODE_BYTES,
713 					     xop->head.mtid, 0, 0);
714 	}
715 done:
716 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
717 	if (parent) {
718 		hammer2_chain_unlock(parent);
719 		hammer2_chain_drop(parent);
720 	}
721 	if (chain) {
722 		hammer2_chain_unlock(chain);
723 		hammer2_chain_drop(chain);
724 	}
725 }
726 
727 /*
728  * Directory collision resolver scan helper (backend, threaded).
729  *
730  * Used by the inode create code to locate an unused lhc.
731  */
732 void
733 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
734 {
735 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
736 	hammer2_chain_t *parent;
737 	hammer2_chain_t *chain;
738 	hammer2_key_t key_next;
739 	int error = 0;
740 
741 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
742 				     HAMMER2_RESOLVE_ALWAYS |
743 				     HAMMER2_RESOLVE_SHARED);
744 	if (parent == NULL) {
745 		kprintf("xop_nresolve: NULL parent\n");
746 		chain = NULL;
747 		error = HAMMER2_ERROR_EIO;
748 		goto done;
749 	}
750 
751 	/*
752 	 * Lookup all possibly conflicting directory entries, the feed
753 	 * inherits the chain's lock so do not unlock it on the iteration.
754 	 */
755 	chain = hammer2_chain_lookup(&parent, &key_next,
756 				     xop->lhc,
757 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
758 				     &error,
759 				     HAMMER2_LOOKUP_ALWAYS |
760 				     HAMMER2_LOOKUP_SHARED);
761 	while (chain) {
762 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
763 		if (error) {
764 			hammer2_chain_unlock(chain);
765 			hammer2_chain_drop(chain);
766 			chain = NULL;	/* safety */
767 			goto done;
768 		}
769 		chain = hammer2_chain_next(&parent, chain, &key_next,
770 					   key_next,
771 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
772 					   &error,
773 					   HAMMER2_LOOKUP_ALWAYS |
774 					   HAMMER2_LOOKUP_SHARED);
775 	}
776 done:
777 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
778 	if (parent) {
779 		hammer2_chain_unlock(parent);
780 		hammer2_chain_drop(parent);
781 	}
782 }
783 
784 /*
785  * Generic lookup of a specific key.
786  *
787  * Used by the inode hidden directory code to find the hidden directory.
788  */
789 void
790 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
791 {
792 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
793 	hammer2_chain_t *parent;
794 	hammer2_chain_t *chain;
795 	hammer2_key_t key_next;
796 	int error = 0;
797 
798 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
799 				     HAMMER2_RESOLVE_ALWAYS |
800 				     HAMMER2_RESOLVE_SHARED);
801 	chain = NULL;
802 	if (parent == NULL) {
803 		error = HAMMER2_ERROR_EIO;
804 		goto done;
805 	}
806 
807 	/*
808 	 * Lookup all possibly conflicting directory entries, the feed
809 	 * inherits the chain's lock so do not unlock it on the iteration.
810 	 */
811 	chain = hammer2_chain_lookup(&parent, &key_next,
812 				     xop->lhc, xop->lhc,
813 				     &error,
814 				     HAMMER2_LOOKUP_ALWAYS |
815 				     HAMMER2_LOOKUP_SHARED);
816 	if (error == 0) {
817 		if (chain)
818 			error = chain->error;
819 		else
820 			error = HAMMER2_ERROR_ENOENT;
821 	}
822 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
823 
824 done:
825 	if (chain) {
826 		hammer2_chain_unlock(chain);
827 		hammer2_chain_drop(chain);
828 	}
829 	if (parent) {
830 		hammer2_chain_unlock(parent);
831 		hammer2_chain_drop(parent);
832 	}
833 }
834 
835 /*
836  * Generic scan
837  *
838  * WARNING! Fed chains must be locked shared so ownership can be transfered
839  *	    and to prevent frontend/backend stalls that would occur with an
840  *	    exclusive lock.  The shared lock also allows chain->data to be
841  *	    retained.
842  */
843 void
844 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
845 {
846 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
847 	hammer2_chain_t *parent;
848 	hammer2_chain_t *chain;
849 	hammer2_key_t key_next;
850 	int error = 0;
851 
852 	/*
853 	 * Assert required flags.
854 	 */
855 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
856 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
857 
858 	/*
859 	 * The inode's chain is the iterator.  If we cannot acquire it our
860 	 * contribution ends here.
861 	 */
862 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
863 				     xop->resolve_flags);
864 	if (parent == NULL) {
865 		kprintf("xop_readdir: NULL parent\n");
866 		goto done;
867 	}
868 
869 	/*
870 	 * Generic scan of exact records.  Note that indirect blocks are
871 	 * automatically recursed and will not be returned.
872 	 */
873 	chain = hammer2_chain_lookup(&parent, &key_next,
874 				     xop->key_beg, xop->key_end,
875 				     &error, xop->lookup_flags);
876 	while (chain) {
877 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
878 		if (error)
879 			goto break2;
880 		chain = hammer2_chain_next(&parent, chain, &key_next,
881 					   key_next, xop->key_end,
882 					   &error, xop->lookup_flags);
883 	}
884 break2:
885 	if (chain) {
886 		hammer2_chain_unlock(chain);
887 		hammer2_chain_drop(chain);
888 	}
889 	hammer2_chain_unlock(parent);
890 	hammer2_chain_drop(parent);
891 done:
892 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
893 }
894