xref: /dragonfly/sys/vfs/hammer2/hammer2_xops.c (revision a3127495)
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.  We
386 			 * ignore chain->error here, allowing an errored
387 			 * chain (aka directory entry) to still be deleted.
388 			 */
389 			error = hammer2_chain_delete(parent, chain,
390 					     xop->head.mtid, dopermanent);
391 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
392 			   (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
393 			/*
394 			 * error may be EAGAIN or ENOTEMPTY
395 			 */
396 			if (error == HAMMER2_ERROR_EAGAIN) {
397 				hammer2_chain_unlock(chain);
398 				hammer2_chain_drop(chain);
399 				hammer2_chain_unlock(parent);
400 				hammer2_chain_drop(parent);
401 				goto again;
402 			}
403 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
404 		    xop->isdir == 0) {
405 			error = HAMMER2_ERROR_ENOTDIR;
406 		} else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
407 			   xop->isdir >= 1) {
408 			error = HAMMER2_ERROR_EISDIR;
409 		} else {
410 			/*
411 			 * Delete the directory entry.  chain might also
412 			 * be a directly-embedded inode.
413 			 *
414 			 * Allow the deletion to proceed even if the chain
415 			 * is errored.  Give priority to error-on-delete over
416 			 * chain->error.
417 			 */
418 			error = hammer2_chain_delete(parent, chain,
419 						     xop->head.mtid,
420 						     dopermanent);
421 			if (error == 0)
422 				error = chain->error;
423 		}
424 	} else {
425 		if (chain && error == 0)
426 			error = chain->error;
427 	}
428 
429 	/*
430 	 * If chain is a directory entry we must resolve it.  We do not try
431 	 * to manipulate the contents as it might not be synchronized with
432 	 * the frontend hammer2_inode_t, nor do we try to lookup the
433 	 * frontend hammer2_inode_t here (we are the backend!).
434 	 */
435 	if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
436 	    (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
437 		int error2;
438 
439 		lhc = chain->bref.embed.dirent.inum;
440 
441 		error2 = hammer2_chain_inode_find(chain->pmp, lhc,
442 						  thr->clindex, 0,
443 						  &parent, &chain);
444 		if (error2) {
445 			kprintf("inode_find: %016jx %p failed\n",
446 				lhc, chain);
447 			error2 = 0;	/* silently ignore */
448 		}
449 		if (error == 0)
450 			error = error2;
451 	}
452 
453 	/*
454 	 * Return the inode target for further action.  Typically used by
455 	 * hammer2_inode_unlink_finisher().
456 	 */
457 done:
458 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
459 	if (chain) {
460 		hammer2_chain_unlock(chain);
461 		hammer2_chain_drop(chain);
462 		chain = NULL;
463 	}
464 	if (parent) {
465 		hammer2_chain_unlock(parent);
466 		hammer2_chain_drop(parent);
467 		parent = NULL;
468 	}
469 }
470 
471 /*
472  * Backend for hammer2_vop_nrename()
473  *
474  * This handles the backend rename operation.  Typically this renames
475  * directory entries but can also be used to rename embedded inodes.
476  *
477  * NOTE! The frontend is responsible for updating the inode meta-data in
478  *	 the file being renamed and for decrementing the target-replaced
479  *	 inode's nlinks, if present.
480  */
481 void
482 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
483 {
484 	hammer2_xop_nrename_t *xop = &arg->xop_nrename;
485 	hammer2_pfs_t *pmp;
486 	hammer2_chain_t *parent;
487 	hammer2_chain_t *chain;
488 	hammer2_chain_t *tmp;
489 	hammer2_inode_t *ip;
490 	hammer2_key_t key_next;
491 	int error;
492 
493 	/*
494 	 * We need the precise parent chain to issue the deletion.
495 	 *
496 	 * If this is a directory entry we must locate the underlying
497 	 * inode.  If it is an embedded inode we can act directly on it.
498 	 */
499 	ip = xop->head.ip2;
500 	pmp = ip->pmp;
501 	chain = NULL;
502 	error = 0;
503 
504 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
505 		/*
506 		 * Find ip's direct parent chain.
507 		 */
508 		chain = hammer2_inode_chain(ip, thr->clindex,
509 					    HAMMER2_RESOLVE_ALWAYS);
510 		if (chain == NULL) {
511 			error = HAMMER2_ERROR_EIO;
512 			parent = NULL;
513 			goto done;
514 		}
515 		parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
516 		if (parent == NULL) {
517 			error = HAMMER2_ERROR_EIO;
518 			goto done;
519 		}
520 	} else {
521 		/*
522 		 * The directory entry for the head.ip1 inode
523 		 * is in fdip, do a namespace search.
524 		 */
525 		hammer2_key_t lhc;
526 		const char *name;
527 		size_t name_len;
528 
529 		parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
530 					     HAMMER2_RESOLVE_ALWAYS);
531 		if (parent == NULL) {
532 			kprintf("xop_nrename: NULL parent\n");
533 			error = HAMMER2_ERROR_EIO;
534 			goto done;
535 		}
536 		name = xop->head.name1;
537 		name_len = xop->head.name1_len;
538 
539 		/*
540 		 * Lookup the directory entry
541 		 */
542 		lhc = hammer2_dirhash(name, name_len);
543 		chain = hammer2_chain_lookup(&parent, &key_next,
544 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
545 					     &error, HAMMER2_LOOKUP_ALWAYS);
546 		while (chain) {
547 			if (hammer2_chain_dirent_test(chain, name, name_len))
548 				break;
549 			chain = hammer2_chain_next(&parent, chain, &key_next,
550 						   key_next,
551 						   lhc + HAMMER2_DIRHASH_LOMASK,
552 						   &error,
553 						   HAMMER2_LOOKUP_ALWAYS);
554 		}
555 	}
556 
557 	if (chain == NULL) {
558 		/* XXX shouldn't happen, but does under fsstress */
559 		kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
560 			xop->head.name1,
561 			xop->head.name2);
562 		if (error == 0)
563 			error = HAMMER2_ERROR_ENOENT;
564 		goto done;
565 	}
566 
567 	if (chain->error) {
568 		error = chain->error;
569 		goto done;
570 	}
571 
572 	/*
573 	 * Delete it, then create it in the new namespace.
574 	 *
575 	 * An error can occur if the chain being deleted requires
576 	 * modification and the media is full.
577 	 */
578 	error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
579 	hammer2_chain_unlock(parent);
580 	hammer2_chain_drop(parent);
581 	parent = NULL;		/* safety */
582 	if (error)
583 		goto done;
584 
585 	/*
586 	 * Adjust fields in the deleted chain appropriate for the rename
587 	 * operation.
588 	 *
589 	 * NOTE! For embedded inodes, the frontend will officially replicate
590 	 *	 the field adjustments, but we also do it here to maintain
591 	 *	 consistency in case of a crash.
592 	 */
593 	if (chain->bref.key != xop->lhc ||
594 	    xop->head.name1_len != xop->head.name2_len ||
595 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
596 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
597 			hammer2_inode_data_t *wipdata;
598 
599 			error = hammer2_chain_modify(chain, xop->head.mtid,
600 						     0, 0);
601 			if (error == 0) {
602 				wipdata = &chain->data->ipdata;
603 
604 				bzero(wipdata->filename,
605 				      sizeof(wipdata->filename));
606 				bcopy(xop->head.name2,
607 				      wipdata->filename,
608 				      xop->head.name2_len);
609 				wipdata->meta.name_key = xop->lhc;
610 				wipdata->meta.name_len = xop->head.name2_len;
611 			}
612 		}
613 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
614 			if (xop->head.name2_len <=
615 			    sizeof(chain->bref.check.buf)) {
616 				/*
617 				 * Remove any related data buffer, we can
618 				 * embed the filename in the bref itself.
619 				 */
620 				error = hammer2_chain_resize(
621 						chain, xop->head.mtid, 0, 0, 0);
622 				if (error == 0) {
623 					error = hammer2_chain_modify(
624 							chain, xop->head.mtid,
625 							0, 0);
626 				}
627 				if (error == 0) {
628 					bzero(chain->bref.check.buf,
629 					      sizeof(chain->bref.check.buf));
630 					bcopy(xop->head.name2,
631 					      chain->bref.check.buf,
632 					      xop->head.name2_len);
633 				}
634 			} else {
635 				/*
636 				 * Associate a data buffer with the bref.
637 				 * Zero it for consistency.  Note that the
638 				 * data buffer is not 64KB so use chain->bytes
639 				 * instead of sizeof().
640 				 */
641 				error = hammer2_chain_resize(
642 					chain, xop->head.mtid, 0,
643 					hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
644 				if (error == 0) {
645 					error = hammer2_chain_modify(
646 						    chain, xop->head.mtid,
647 						    0, 0);
648 				}
649 				if (error == 0) {
650 					bzero(chain->data->buf, chain->bytes);
651 					bcopy(xop->head.name2,
652 					      chain->data->buf,
653 					      xop->head.name2_len);
654 				}
655 			}
656 			if (error == 0) {
657 				chain->bref.embed.dirent.namlen =
658 					xop->head.name2_len;
659 			}
660 		}
661 	}
662 
663 	/*
664 	 * The frontend will replicate this operation and is the real final
665 	 * authority, but adjust the inode's iparent field too if the inode
666 	 * is embedded in the directory.
667 	 */
668 	if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
669 	    chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
670 		hammer2_inode_data_t *wipdata;
671 
672 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
673 		if (error == 0) {
674 			wipdata = &chain->data->ipdata;
675 			wipdata->meta.iparent = xop->head.ip3->meta.inum;
676 		}
677 	}
678 
679 	/*
680 	 * Destroy any matching target(s) before creating the new entry.
681 	 * This will result in some ping-ponging of the directory key
682 	 * iterator but that is ok.
683 	 */
684 	parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
685 				     HAMMER2_RESOLVE_ALWAYS);
686 	if (parent == NULL) {
687 		error = HAMMER2_ERROR_EIO;
688 		goto done;
689 	}
690 
691 	/*
692 	 * Delete all matching directory entries.  That is, get rid of
693 	 * multiple duplicates if present, as a self-healing mechanism.
694 	 */
695 	if (error == 0) {
696 		tmp = hammer2_chain_lookup(&parent, &key_next,
697 					   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
698 					   xop->lhc | HAMMER2_DIRHASH_LOMASK,
699 					   &error,
700 					   HAMMER2_LOOKUP_ALWAYS);
701 		while (tmp) {
702 			int e2;
703 			if (hammer2_chain_dirent_test(tmp, xop->head.name2,
704 						      xop->head.name2_len)) {
705 				e2 = hammer2_chain_delete(parent, tmp,
706 							  xop->head.mtid, 0);
707 				if (error == 0 && e2)
708 					error = e2;
709 			}
710 			tmp = hammer2_chain_next(&parent, tmp, &key_next,
711 						 key_next,
712 						 xop->lhc |
713 						  HAMMER2_DIRHASH_LOMASK,
714 						 &error,
715 						 HAMMER2_LOOKUP_ALWAYS);
716 		}
717 	}
718 	if (error == 0) {
719 		/*
720 		 * A relookup is required before the create to properly
721 		 * position the parent chain.
722 		 */
723 		tmp = hammer2_chain_lookup(&parent, &key_next,
724 					   xop->lhc, xop->lhc,
725 					   &error, 0);
726 		KKASSERT(tmp == NULL);
727 		error = hammer2_chain_create(&parent, &chain,
728 					     pmp, HAMMER2_METH_DEFAULT,
729 					     xop->lhc, 0,
730 					     HAMMER2_BREF_TYPE_INODE,
731 					     HAMMER2_INODE_BYTES,
732 					     xop->head.mtid, 0, 0);
733 	}
734 done:
735 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
736 	if (parent) {
737 		hammer2_chain_unlock(parent);
738 		hammer2_chain_drop(parent);
739 	}
740 	if (chain) {
741 		hammer2_chain_unlock(chain);
742 		hammer2_chain_drop(chain);
743 	}
744 }
745 
746 /*
747  * Directory collision resolver scan helper (backend, threaded).
748  *
749  * Used by the inode create code to locate an unused lhc.
750  */
751 void
752 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
753 {
754 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
755 	hammer2_chain_t *parent;
756 	hammer2_chain_t *chain;
757 	hammer2_key_t key_next;
758 	int error = 0;
759 
760 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
761 				     HAMMER2_RESOLVE_ALWAYS |
762 				     HAMMER2_RESOLVE_SHARED);
763 	if (parent == NULL) {
764 		kprintf("xop_nresolve: NULL parent\n");
765 		chain = NULL;
766 		error = HAMMER2_ERROR_EIO;
767 		goto done;
768 	}
769 
770 	/*
771 	 * Lookup all possibly conflicting directory entries, the feed
772 	 * inherits the chain's lock so do not unlock it on the iteration.
773 	 */
774 	chain = hammer2_chain_lookup(&parent, &key_next,
775 				     xop->lhc,
776 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
777 				     &error,
778 				     HAMMER2_LOOKUP_ALWAYS |
779 				     HAMMER2_LOOKUP_SHARED);
780 	while (chain) {
781 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
782 		if (error) {
783 			hammer2_chain_unlock(chain);
784 			hammer2_chain_drop(chain);
785 			chain = NULL;	/* safety */
786 			goto done;
787 		}
788 		chain = hammer2_chain_next(&parent, chain, &key_next,
789 					   key_next,
790 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
791 					   &error,
792 					   HAMMER2_LOOKUP_ALWAYS |
793 					   HAMMER2_LOOKUP_SHARED);
794 	}
795 done:
796 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
797 	if (parent) {
798 		hammer2_chain_unlock(parent);
799 		hammer2_chain_drop(parent);
800 	}
801 }
802 
803 /*
804  * Generic lookup of a specific key.
805  *
806  * Used by the inode hidden directory code to find the hidden directory.
807  */
808 void
809 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
810 {
811 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
812 	hammer2_chain_t *parent;
813 	hammer2_chain_t *chain;
814 	hammer2_key_t key_next;
815 	int error = 0;
816 
817 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
818 				     HAMMER2_RESOLVE_ALWAYS |
819 				     HAMMER2_RESOLVE_SHARED);
820 	chain = NULL;
821 	if (parent == NULL) {
822 		error = HAMMER2_ERROR_EIO;
823 		goto done;
824 	}
825 
826 	/*
827 	 * Lookup all possibly conflicting directory entries, the feed
828 	 * inherits the chain's lock so do not unlock it on the iteration.
829 	 */
830 	chain = hammer2_chain_lookup(&parent, &key_next,
831 				     xop->lhc, xop->lhc,
832 				     &error,
833 				     HAMMER2_LOOKUP_ALWAYS |
834 				     HAMMER2_LOOKUP_SHARED);
835 	if (error == 0) {
836 		if (chain)
837 			error = chain->error;
838 		else
839 			error = HAMMER2_ERROR_ENOENT;
840 	}
841 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
842 
843 done:
844 	if (chain) {
845 		hammer2_chain_unlock(chain);
846 		hammer2_chain_drop(chain);
847 	}
848 	if (parent) {
849 		hammer2_chain_unlock(parent);
850 		hammer2_chain_drop(parent);
851 	}
852 }
853 
854 /*
855  * Generic scan
856  *
857  * WARNING! Fed chains must be locked shared so ownership can be transfered
858  *	    and to prevent frontend/backend stalls that would occur with an
859  *	    exclusive lock.  The shared lock also allows chain->data to be
860  *	    retained.
861  */
862 void
863 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
864 {
865 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
866 	hammer2_chain_t *parent;
867 	hammer2_chain_t *chain;
868 	hammer2_key_t key_next;
869 	int error = 0;
870 
871 	/*
872 	 * Assert required flags.
873 	 */
874 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
875 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
876 
877 	/*
878 	 * The inode's chain is the iterator.  If we cannot acquire it our
879 	 * contribution ends here.
880 	 */
881 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
882 				     xop->resolve_flags);
883 	if (parent == NULL) {
884 		kprintf("xop_readdir: NULL parent\n");
885 		goto done;
886 	}
887 
888 	/*
889 	 * Generic scan of exact records.  Note that indirect blocks are
890 	 * automatically recursed and will not be returned.
891 	 */
892 	chain = hammer2_chain_lookup(&parent, &key_next,
893 				     xop->key_beg, xop->key_end,
894 				     &error, xop->lookup_flags);
895 	while (chain) {
896 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
897 		if (error)
898 			goto break2;
899 		chain = hammer2_chain_next(&parent, chain, &key_next,
900 					   key_next, xop->key_end,
901 					   &error, xop->lookup_flags);
902 	}
903 break2:
904 	if (chain) {
905 		hammer2_chain_unlock(chain);
906 		hammer2_chain_drop(chain);
907 	}
908 	hammer2_chain_unlock(parent);
909 	hammer2_chain_drop(parent);
910 done:
911 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
912 }
913