xref: /titanic_44/usr/src/cmd/fs.d/cachefs/cfsd/cfsd_fscache.c (revision c28749e97052f09388969427adf7df641cdcdc22)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1994-2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Methods of the cfsd_fscache class.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stddef.h>
37 #include <thread.h>
38 #include <synch.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <stdarg.h>
42 #include <limits.h>
43 #include <fcntl.h>
44 #include <locale.h>
45 #include <nfs/nfs.h>
46 #include <sys/utsname.h>
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <sys/mount.h>
50 #include <sys/types.h>
51 #include <sys/wait.h>
52 #include <rpc/rpc.h>
53 #include <mdbug/mdbug.h>
54 #include <sys/fs/cachefs_fs.h>
55 #include <sys/fs/cachefs_dlog.h>
56 #include <sys/fs/cachefs_ioctl.h>
57 #include "cfsd.h"
58 #include "cfsd_kmod.h"
59 #include "cfsd_maptbl.h"
60 #include "cfsd_logfile.h"
61 #include "cfsd_logelem.h"
62 #include "cfsd_fscache.h"
63 
64 /*
65  * -----------------------------------------------------------------
66  *			cfsd_fscache_create
67  *
68  * Description:
69  * Arguments:
70  *	name
71  *	cachepath
72  * Returns:
73  * Preconditions:
74  *	precond(name)
75  *	precond(cachepath)
76  */
77 cfsd_fscache_object_t *
78 cfsd_fscache_create(const char *name, const char *cachepath,
79 	int fscacheid)
80 {
81 	cfsd_fscache_object_t *fscache_object_p;
82 	int xx;
83 
84 	dbug_enter("cfsd_fscache_create");
85 
86 	dbug_precond(name);
87 	dbug_precond(cachepath);
88 
89 	fscache_object_p = cfsd_calloc(sizeof (cfsd_fscache_object_t));
90 	strlcpy(fscache_object_p->i_name, name,
91 	    sizeof (fscache_object_p->i_name));
92 	strlcpy(fscache_object_p->i_cachepath, cachepath,
93 	    sizeof (fscache_object_p->i_cachepath));
94 	fscache_object_p->i_fscacheid = fscacheid;
95 	fscache_object_p->i_refcnt = 0;
96 	fscache_object_p->i_disconnectable = 0;
97 	fscache_object_p->i_mounted = 0;
98 	fscache_object_p->i_threaded = 0;
99 	fscache_object_p->i_connected = 0;
100 	fscache_object_p->i_reconcile = 0;
101 	fscache_object_p->i_changes = 0;
102 	fscache_object_p->i_simdis = 0;
103 	fscache_object_p->i_tryunmount = 0;
104 	fscache_object_p->i_backunmount = 0;
105 	fscache_object_p->i_time_state = 0;
106 	fscache_object_p->i_time_mnt = 0;
107 	fscache_object_p->i_modify = 1;
108 
109 	fscache_object_p->i_threadid = 0;
110 	fscache_object_p->i_ofd = -1;
111 
112 	fscache_object_p->i_next = NULL;
113 
114 	/* initialize the locking mutex */
115 	xx = mutex_init(&fscache_object_p->i_lock, USYNC_THREAD, NULL);
116 	dbug_assert(xx == 0);
117 
118 	xx = cond_init(&fscache_object_p->i_cvwait, USYNC_THREAD, 0);
119 	dbug_assert(xx == 0);
120 
121 	dbug_leave("cfsd_fscache_create");
122 	return (fscache_object_p);
123 }
124 
125 /*
126  * -----------------------------------------------------------------
127  *			cfsd_fscache_destroy
128  *
129  * Description:
130  * Arguments:
131  * Returns:
132  * Preconditions:
133  */
134 void
135 cfsd_fscache_destroy(cfsd_fscache_object_t *fscache_object_p)
136 {
137 	int xx;
138 
139 	dbug_enter("cfsd_fscache_destroy");
140 
141 	dbug_precond(fscache_object_p);
142 	/* dbug_assert(fscache_object_p->i_refcnt == 0); */
143 
144 	/* close down the message file descriptor */
145 	if (fscache_object_p->i_ofd >= 0) {
146 		if (close(fscache_object_p->i_ofd))
147 			dbug_print(("error", "cannot close fscache fd error %d",
148 			    errno));
149 		fscache_object_p->i_ofd = -1;
150 	}
151 
152 	/* destroy the locking mutex */
153 	xx = mutex_destroy(&fscache_object_p->i_lock);
154 	dbug_assert(xx == 0);
155 
156 	/* destroy the conditional variable */
157 	xx = cond_destroy(&fscache_object_p->i_cvwait);
158 	dbug_assert(xx == 0);
159 
160 	cfsd_free(fscache_object_p);
161 
162 	dbug_leave("cfsd_fscache_destroy");
163 }
164 
165 /*
166  * -----------------------------------------------------------------
167  *			fscache_lock
168  *
169  * Description:
170  * Arguments:
171  * Returns:
172  * Preconditions:
173  */
174 void
175 fscache_lock(cfsd_fscache_object_t *fscache_object_p)
176 {
177 	dbug_enter("fscache_lock");
178 
179 	dbug_precond(fscache_object_p);
180 	mutex_lock(&fscache_object_p->i_lock);
181 	dbug_leave("fscache_lock");
182 }
183 
184 /*
185  * -----------------------------------------------------------------
186  *			fscache_unlock
187  *
188  * Description:
189  * Arguments:
190  * Returns:
191  * Preconditions:
192  */
193 void
194 fscache_unlock(cfsd_fscache_object_t *fscache_object_p)
195 {
196 	dbug_enter("fscache_unlock");
197 
198 	dbug_precond(fscache_object_p);
199 	mutex_unlock(&fscache_object_p->i_lock);
200 	dbug_leave("fscache_unlock");
201 }
202 
203 /*
204  * -----------------------------------------------------------------
205  *			fscache_setup
206  *
207  * Description:
208  * Arguments:
209  * Returns:
210  * Preconditions:
211  */
212 void
213 fscache_setup(cfsd_fscache_object_t *fscache_object_p)
214 {
215 	char *tmp;
216 	char cfs_mnt_filename[MAXPATHLEN];
217 	FILE *fin;
218 	/*
219 	 * Line input buffer allows for type field (magic number size
220 	 * of 50 is historic), the field separator ": ", a large value
221 	 * (again historic) and a '\n' character.
222 	 */
223 	char type[50];
224 	char value[MAXPATHLEN * 4];
225 	char buf[sizeof (type) + 2 + sizeof (value) + 1];
226 	int err = 0;
227 	int xx;
228 	char *options[] = { "snr", "disconnectable", NULL };
229 	char *strp = buf;
230 	char *dummy;
231 	struct stat64 sinfo;
232 	time_t mtime;
233 
234 	dbug_enter("fscache_setup");
235 	dbug_precond(fscache_object_p);
236 
237 	fscache_object_p->i_modify++;
238 	fscache_object_p->i_disconnectable = 0;
239 	fscache_object_p->i_connected = 0;
240 	fscache_object_p->i_reconcile = 0;
241 	fscache_object_p->i_changes = 0;
242 	fscache_object_p->i_time_state = 0;
243 	fscache_object_p->i_time_mnt = 0;
244 	fscache_object_p->i_mntpt[0] = '\0';
245 	fscache_object_p->i_backfs[0] = '\0';
246 	fscache_object_p->i_backpath[0] = '\0';
247 	fscache_object_p->i_backfstype[0] = '\0';
248 	fscache_object_p->i_cfsopt[0] = '\0';
249 	fscache_object_p->i_bfsopt[0] = '\0';
250 
251 	snprintf(cfs_mnt_filename, sizeof (cfs_mnt_filename), "%s/%s/%s",
252 	    fscache_object_p->i_cachepath, fscache_object_p->i_name,
253 	    CACHEFS_MNT_FILE);
254 
255 	/* open for reading the file with the mount information */
256 	fin = fopen(cfs_mnt_filename, "r");
257 	if (fin == NULL) {
258 		dbug_print(("err", "could not open %s, %d", cfs_mnt_filename,
259 		    errno));
260 		dbug_leave("fscache_setup");
261 		return;
262 	}
263 	/* get the modify time of the mount file */
264 	if (fstat64(fileno(fin), &sinfo) == -1) {
265 		dbug_print(("err", "could not stat %s, %d", cfs_mnt_filename,
266 		    errno));
267 		if (fclose(fin))
268 			dbug_print(("err", "cannot close %s, %d",
269 			    cfs_mnt_filename, errno));
270 		dbug_leave("fscache_setup");
271 		return;
272 	}
273 	mtime = sinfo.st_mtime;
274 
275 	/* read the mount information from the file */
276 	while (fgets(buf, sizeof (buf), fin) != NULL) {
277 		tmp = strtok(buf, ":");
278 		if (strlcpy(type, tmp, sizeof (type)) >= sizeof (type)) {
279 			/* Buffer Overflow */
280 			dbug_print(("err", "overflow in type field"
281 			    " of file %s", cfs_mnt_filename));
282 			if (fclose(fin))
283 				dbug_print(("err", "cannot close %s, %d",
284 				    cfs_mnt_filename, errno));
285 			dbug_leave("fscache_setup");
286 			return;
287 		}
288 		tmp = strtok(NULL, "\n");
289 		if (tmp != NULL && *tmp == ' ') {
290 			/*
291 			 * There is a valid value string so skip
292 			 * the space after the ":".
293 			 */
294 			tmp++;
295 			if (strlcpy(value, tmp, sizeof (value))
296 			    >= sizeof (value)) {
297 				/* Buffer Overflow */
298 				dbug_print(("err",
299 				    "overflow in value field"
300 				    " of file %s", cfs_mnt_filename));
301 				if (fclose(fin))
302 					dbug_print(("err",
303 					    "cannot close %s, %d",
304 					    cfs_mnt_filename, errno));
305 				dbug_leave("fscache_setup");
306 				return;
307 			}
308 		} else {
309 			value[0] = '\0';
310 		}
311 		dbug_print(("info", "\"%s\" \"%s\"", type, value));
312 		if (strcmp(type, "cachedir") == 0) {
313 			if (strcmp(fscache_object_p->i_cachepath, value) != 0) {
314 				err = 1;
315 				dbug_print(("err", "caches do not match %s, %s",
316 				    fscache_object_p->i_cachepath, buf));
317 			}
318 		} else if (strcmp(type, "mnt_point") == 0) {
319 			strlcpy(fscache_object_p->i_mntpt, value,
320 			    sizeof (fscache_object_p->i_mntpt));
321 		} else if (strcmp(type, "special") == 0) {
322 			strlcpy(fscache_object_p->i_backfs, value,
323 			    sizeof (fscache_object_p->i_backfs));
324 		} else if (strcmp(type, "backpath") == 0) {
325 			strlcpy(fscache_object_p->i_backpath, value,
326 			    sizeof (fscache_object_p->i_backpath));
327 		} else if (strcmp(type, "backfstype") == 0) {
328 			strlcpy(fscache_object_p->i_backfstype, value,
329 			    sizeof (fscache_object_p->i_backfstype));
330 		} else if (strcmp(type, "cacheid") == 0) {
331 			if (strcmp(fscache_object_p->i_name, value) != 0) {
332 				err = 1;
333 				dbug_print(("err", "ids do not match %s, %s",
334 				    fscache_object_p->i_name, value));
335 			}
336 		} else if (strcmp(type, "cachefs_options") == 0) {
337 			strlcpy(fscache_object_p->i_cfsopt, value,
338 			    sizeof (fscache_object_p->i_cfsopt));
339 		} else if (strcmp(type, "backfs_options") == 0) {
340 			strlcpy(fscache_object_p->i_bfsopt, value,
341 			    sizeof (fscache_object_p->i_bfsopt));
342 		} else if (strcmp(type, "mount_time") == 0) {
343 			continue;
344 		} else {
345 			dbug_print(("err", "unknown keyword \"%s\"", type));
346 			err = 1;
347 		}
348 	}
349 	if (fclose(fin))
350 		dbug_print(("err", "cannot close %s, %d",
351 		    cfs_mnt_filename, errno));
352 
353 	/* see if this is a file system that is disconnectable */
354 	if ((err == 0) &&
355 		(fscache_object_p->i_backfs[0] &&
356 		fscache_object_p->i_cfsopt[0])) {
357 		strlcpy(buf, fscache_object_p->i_cfsopt, sizeof (buf));
358 		while (*strp != '\0') {
359 			xx = getsubopt(&strp, options, &dummy);
360 			if (xx != -1) {
361 				fscache_object_p->i_disconnectable = 1;
362 				break;
363 			}
364 		}
365 	}
366 
367 	/*
368 	 * open up a fd on the sysmsg so we have a place to write
369 	 * log rolling errors
370 	 */
371 	if (fscache_object_p->i_disconnectable) {
372 		if (fscache_object_p->i_ofd < 0)
373 			fscache_object_p->i_ofd = open("/dev/sysmsg",
374 			    O_WRONLY);
375 		if (fscache_object_p->i_ofd < 0) {
376 			fprintf(stderr,
377 			    gettext("cachefsd: File system %s cannot be"
378 			    " disconnected.\n"),
379 			    fscache_object_p->i_mntpt);
380 			fprintf(stderr,
381 			    gettext("cachefsd: Cannot open /dev/sysmsg\n"));
382 			fscache_object_p->i_disconnectable = 0;
383 		}
384 	}
385 
386 	/* see if the file system is mounted */
387 	snprintf(cfs_mnt_filename, sizeof (cfs_mnt_filename), "%s/%s/%s",
388 	    fscache_object_p->i_cachepath, fscache_object_p->i_name,
389 	    CACHEFS_UNMNT_FILE);
390 	if (stat64(cfs_mnt_filename, &sinfo) == 0) {
391 		fscache_object_p->i_mounted = 0;
392 		mtime = sinfo.st_mtime;
393 	} else
394 		fscache_object_p->i_mounted = 1;
395 
396 	/* save the time of the last mount or unmount */
397 	fscache_object_p->i_time_mnt = mtime;
398 
399 	dbug_print(("info", "disconnectable == %d, mounted == %d",
400 	    fscache_object_p->i_disconnectable,
401 	    fscache_object_p->i_mounted));
402 	dbug_leave("fscache_setup");
403 }
404 
405 /*
406  * -----------------------------------------------------------------
407  *			fscache_process
408  *
409  * Description:
410  * Arguments:
411  * Returns:
412  * Preconditions:
413  */
414 void
415 fscache_process(cfsd_fscache_object_t *fscache_object_p)
416 {
417 	int xx;
418 	int changes;
419 	cfsd_kmod_object_t *kmod_object_p;
420 	int setup = 1;
421 	int state;
422 
423 	dbug_enter("fscache_process");
424 	dbug_precond(fscache_object_p);
425 
426 	kmod_object_p = cfsd_kmod_create();
427 	for (;;) {
428 		fscache_lock(fscache_object_p);
429 		fscache_object_p->i_time_state = time(NULL);
430 		fscache_object_p->i_modify++;
431 
432 		/* if we should try to unmount the file system */
433 		if (fscache_object_p->i_tryunmount) {
434 			/* shut down the interface to the kmod */
435 			if (setup == 0) {
436 				kmod_shutdown(kmod_object_p);
437 				setup = 1;
438 			}
439 
440 			/* try to unmount the file system */
441 			if (umount(fscache_object_p->i_mntpt) == -1) {
442 				xx = errno;
443 				dbug_print(("info", "unmount failed %s",
444 				    strerror(xx)));
445 			} else {
446 				fscache_object_p->i_mounted = 0;
447 			}
448 
449 			/* wake up thread blocked in fscache_unmount */
450 			fscache_object_p->i_tryunmount = 0;
451 			xx = cond_broadcast(&fscache_object_p->i_cvwait);
452 			dbug_assert(xx == 0);
453 
454 			/* all done if unmount succeeded */
455 			if (fscache_object_p->i_mounted == 0) {
456 				fscache_unlock(fscache_object_p);
457 				break;
458 			}
459 		}
460 
461 		if (setup) {
462 			setup = 0;
463 			/*
464 			 * make an interface into the cachefs kmod for
465 			 * this fs
466 			 */
467 			xx = kmod_setup(kmod_object_p,
468 			    fscache_object_p->i_mntpt);
469 			if (xx != 0) {
470 				dbug_print(("err",
471 				    "setup of kmod interface failed %d", xx));
472 				fscache_object_p->i_disconnectable = 0;
473 				fscache_object_p->i_modify++;
474 				fscache_unlock(fscache_object_p);
475 				break;
476 			}
477 
478 			/* verify that we got the file system we expected XXX */
479 		}
480 
481 		/* get the current state of the file system */
482 		state = kmod_stateget(kmod_object_p);
483 
484 		if (fscache_object_p->i_simdis && (state == CFS_FS_CONNECTED)) {
485 			dbug_print(("simdis", "simulating disconnection on %s",
486 			    fscache_object_p->i_mntpt));
487 			xx = kmod_stateset(kmod_object_p, CFS_FS_DISCONNECTED);
488 			dbug_assert(xx == 0);
489 			state = kmod_stateget(kmod_object_p);
490 			dbug_assert(state == CFS_FS_DISCONNECTED);
491 		}
492 		fscache_unlock(fscache_object_p);
493 
494 		switch (state) {
495 		case CFS_FS_CONNECTED:
496 			fscache_lock(fscache_object_p);
497 			fscache_object_p->i_connected = 1;
498 			fscache_object_p->i_reconcile = 0;
499 			fscache_object_p->i_modify++;
500 			fscache_unlock(fscache_object_p);
501 
502 			/* wait for fs to switch to disconnecting */
503 			dbug_print(("info", "about to xwait"));
504 			xx = kmod_xwait(kmod_object_p);
505 			if (xx == EINTR) {
506 				dbug_print(("info", "a. EINTR from xwait"));
507 				continue;
508 			}
509 			dbug_assert(xx == 0);
510 			state = kmod_stateget(kmod_object_p);
511 			dbug_assert(state == CFS_FS_DISCONNECTED);
512 			break;
513 
514 		case CFS_FS_DISCONNECTED:
515 			fscache_lock(fscache_object_p);
516 			fscache_object_p->i_connected = 0;
517 			fscache_object_p->i_reconcile = 0;
518 			fscache_object_p->i_modify++;
519 			fscache_unlock(fscache_object_p);
520 
521 			/* wait until we are reconnected */
522 			fscache_server_alive(fscache_object_p, kmod_object_p);
523 			if (fscache_object_p->i_tryunmount)
524 				continue;
525 
526 			/* switch to reconnecting mode */
527 			xx = kmod_stateset(kmod_object_p, CFS_FS_RECONNECTING);
528 			dbug_assert(xx == 0);
529 			break;
530 
531 		case CFS_FS_RECONNECTING:
532 			fscache_lock(fscache_object_p);
533 			fscache_object_p->i_connected = 1;
534 			fscache_object_p->i_reconcile = 1;
535 			fscache_object_p->i_modify++;
536 			changes = fscache_object_p->i_changes;
537 			fscache_unlock(fscache_object_p);
538 
539 			/* roll the log */
540 			xx = fscache_roll(fscache_object_p, kmod_object_p);
541 			if (xx) {
542 				dbug_assert(xx == ETIMEDOUT);
543 				/* switch to disconnected */
544 				xx = kmod_stateset(kmod_object_p,
545 				    CFS_FS_DISCONNECTED);
546 				dbug_assert(xx == 0);
547 			} else {
548 				/* switch to connected */
549 				xx = kmod_stateset(kmod_object_p,
550 				    CFS_FS_CONNECTED);
551 				dbug_assert(xx == 0);
552 				changes = 0;
553 			}
554 
555 			fscache_lock(fscache_object_p);
556 			fscache_object_p->i_reconcile = 0;
557 			fscache_changes(fscache_object_p, changes);
558 			fscache_object_p->i_modify++;
559 			fscache_unlock(fscache_object_p);
560 
561 			break;
562 
563 		default:
564 			dbug_assert(0);
565 			break;
566 		}
567 	}
568 	cfsd_kmod_destroy(kmod_object_p);
569 	dbug_leave("fscache_process");
570 }
571 
572 /*
573  *			fscache_simdisconnect
574  *
575  * Description:
576  *	Simulates disconnection or reconnects from a simulated disconnection.
577  * Arguments:
578  *	disconnect	1 means disconnect, !1 means connect
579  * Returns:
580  *	Returns 0 for success, !0 on an error
581  * Preconditions:
582  */
583 int
584 fscache_simdisconnect(cfsd_fscache_object_t *fscache_object_p, int disconnect)
585 {
586 
587 	int xx;
588 	int ret = 0;
589 	char *strp;
590 	int tcon;
591 	int trec;
592 
593 	dbug_enter("fscache_simdisconnect");
594 	dbug_precond(fscache_object_p);
595 
596 	strp = disconnect ? "disconnection" : "reconnection";
597 
598 	dbug_print(("simdis", "About to simulate %s", strp));
599 
600 	fscache_lock(fscache_object_p);
601 
602 	if (disconnect) {
603 		/* if file system cannot be disconnected */
604 		if (fscache_object_p->i_disconnectable == 0) {
605 			ret = 1;
606 			goto out;
607 		}
608 
609 		/* if file system is already disconnected */
610 		if (fscache_object_p->i_connected == 0) {
611 			ret = 2;
612 			goto out;
613 		}
614 		fscache_object_p->i_simdis = 1;
615 	} else {
616 		/* if file system is already connected */
617 		if (fscache_object_p->i_connected) {
618 			ret = 1;
619 			goto out;
620 		}
621 
622 		/* if file system is not "simulated" disconnected */
623 		if (fscache_object_p->i_simdis == 0) {
624 			ret = 2;
625 			goto out;
626 		}
627 		fscache_object_p->i_simdis = 0;
628 	}
629 
630 	/* if fs thread not running */
631 	if (fscache_object_p->i_threaded == 0) {
632 		if (fscache_object_p->i_mounted) {
633 			dbug_print(("simdis", "thread not running"));
634 			ret = -1;
635 		} else {
636 			if (fscache_object_p->i_simdis)
637 				fscache_object_p->i_connected = 0;
638 			else
639 				fscache_object_p->i_connected = 1;
640 		}
641 		goto out;
642 	}
643 
644 	/* get the attention of the thread */
645 	dbug_print(("info", "thread %d, killing %d with sigusr1",
646 	    thr_self(), fscache_object_p->i_threadid));
647 	xx = thr_kill(fscache_object_p->i_threadid, SIGUSR1);
648 	if (xx) {
649 		dbug_print(("simdis", "thr_kill failed %d, threadid %d",
650 		    xx, fscache_object_p->i_threadid));
651 		ret = -1;
652 	}
653 
654 out:
655 	fscache_unlock(fscache_object_p);
656 
657 	if (ret == 0) {
658 		for (;;) {
659 			dbug_print(("simdis", "     waiting for simulated %s",
660 			    strp));
661 			fscache_lock(fscache_object_p);
662 			tcon = fscache_object_p->i_connected;
663 			trec = fscache_object_p->i_reconcile;
664 			fscache_unlock(fscache_object_p);
665 			if (disconnect) {
666 				if (tcon == 0)
667 					break;
668 			} else {
669 				if ((tcon == 1) && (trec == 0))
670 					break;
671 			}
672 			cfsd_sleep(1);
673 		}
674 		dbug_print(("simdis", "DONE waiting for simulated %s", strp));
675 	} else {
676 		dbug_print(("simdis", "simulated %s failed %d", strp, ret));
677 	}
678 
679 	dbug_leave("fscache_simdisconnect");
680 	return (ret);
681 }
682 
683 /*
684  *			fscache_unmount
685  *
686  * Description:
687  *	Called to unmount the file system.
688  * Arguments:
689  * Returns:
690  *	Returns 0 if the unmount is successful
691  *		EIO if an error
692  *		EBUSY if did not unmount because busy
693  *		EAGAIN if umounted but should not unmount nfs mount
694  *		ENOTSUP -  forced unmount is not supported by cachefs
695  * Preconditions:
696  */
697 
698 int
699 fscache_unmount(cfsd_fscache_object_t *fscache_object_p, int flag)
700 {
701 	int xx;
702 	int ret = 0;
703 
704 	dbug_enter("fscache_unmount");
705 	dbug_precond(fscache_object_p);
706 
707 	fscache_lock(fscache_object_p);
708 
709 	/* if there is a thread running */
710 	if (fscache_object_p->i_threaded) {
711 		/* do not bother unmounting if rolling the log */
712 		if (fscache_object_p->i_reconcile) {
713 			ret = EBUSY;
714 			goto out;
715 		}
716 
717 		/* inform the thread to try the unmount */
718 		fscache_object_p->i_tryunmount = 1;
719 		fscache_object_p->i_modify++;
720 
721 		/* get the attention of the thread */
722 		dbug_print(("info", "about to do umount kill"));
723 		xx = thr_kill(fscache_object_p->i_threadid, SIGUSR1);
724 		if (xx) {
725 			dbug_print(("error", "thr_kill failed %d, threadid %d",
726 			    xx, fscache_object_p->i_threadid));
727 			ret = EIO;
728 			goto out;
729 		}
730 
731 		/* wait for the thread to wake us up */
732 		while (fscache_object_p->i_tryunmount) {
733 			xx = cond_wait(&fscache_object_p->i_cvwait,
734 			    &fscache_object_p->i_lock);
735 			dbug_print(("info", "cond_wait woke up %d %d",
736 			    xx, fscache_object_p->i_tryunmount));
737 		}
738 
739 		/* if the file system is still mounted */
740 		if (fscache_object_p->i_mounted)
741 			ret = EBUSY;
742 	}
743 
744 	/* else if there is no thread running */
745 	else {
746 		/* try to unmount the file system */
747 		if (umount2(fscache_object_p->i_mntpt, flag) == -1) {
748 			xx = errno;
749 			dbug_print(("info", "unmount failed %s",
750 			    strerror(xx)));
751 			if (xx == EBUSY)
752 				ret = EBUSY;
753 			else if (xx == ENOTSUP)
754 				ret = ENOTSUP;
755 			else
756 				ret = EIO;
757 		} else {
758 			fscache_object_p->i_mounted = 0;
759 			fscache_object_p->i_modify++;
760 		}
761 	}
762 out:
763 	fscache_unlock(fscache_object_p);
764 	dbug_leave("fscache_unmount");
765 	return (ret);
766 }
767 
768 /*
769  * -----------------------------------------------------------------
770  *			fscache_server_alive
771  *
772  * Description:
773  * Arguments:
774  * Returns:
775  * Preconditions:
776  */
777 void
778 fscache_server_alive(cfsd_fscache_object_t *fscache_object_p,
779 	cfsd_kmod_object_t *kmod_object_p)
780 {
781 
782 	int xx;
783 	cfs_fid_t rootfid;
784 	dl_cred_t cr;
785 	cfs_vattr_t va;
786 	char cfsopt[CFS_MAXMNTOPTLEN];
787 	int child_pid;
788 	int stat_loc;
789 
790 	dbug_enter("fscache_server_alive");
791 
792 	dbug_precond(fscache_object_p);
793 	dbug_precond(kmod_object_p);
794 
795 	for (;;) {
796 		/* wait for a little while */
797 		if (fscache_object_p->i_simdis == 0)
798 			cfsd_sleep(30);
799 		/* if simulating disconnect */
800 		fscache_lock(fscache_object_p);
801 		while (fscache_object_p->i_simdis &&
802 			!fscache_object_p->i_tryunmount) {
803 			dbug_print(("simdis", "before calling cond_wait"));
804 			xx = cond_wait(&fscache_object_p->i_cvwait,
805 			    &fscache_object_p->i_lock);
806 			dbug_print(("simdis", "cond_wait woke up %d %d",
807 			    xx, fscache_object_p->i_simdis));
808 		}
809 		fscache_unlock(fscache_object_p);
810 
811 		if (fscache_object_p->i_tryunmount)
812 			break;
813 
814 		/* see if the server is alive */
815 		if (fscache_pingserver(fscache_object_p) == -1) {
816 			/* dead server */
817 			continue;
818 		}
819 
820 		/* try to mount the back file system if needed */
821 		if (fscache_object_p->i_backpath[0] == '\0') {
822 			dbug_precond(fscache_object_p->i_cfsopt[0]);
823 			dbug_precond(fscache_object_p->i_backfs[0]);
824 			dbug_precond(fscache_object_p->i_mntpt[0]);
825 
826 			snprintf(cfsopt, sizeof (cfsopt), "%s,slide,remount",
827 			    fscache_object_p->i_cfsopt);
828 			/*
829 			 * Mounting of a cachefs file system is done by calling
830 			 * out to /usr/lib/fs/cachefs/mount so that mounts
831 			 * done by the user, autofs and by us here in cachefsd
832 			 * are consistent.
833 			 */
834 			switch ((child_pid = fork1())) {
835 			case -1:
836 				/*
837 				 * The original code used system()
838 				 * but never checked for an error
839 				 * occurring. The rest of the code
840 				 * would suggest that "continue" is
841 				 * the correct thing to do.
842 				 */
843 				dbug_print(("info", "unable to fork mount "
844 				    "process for back fs %s %d",
845 				    fscache_object_p->i_backfs, errno));
846 				continue;
847 			case 0:
848 				(void) setsid();
849 				execl("/usr/sbin/mount", "mount", "-F",
850 				    "cachefs", "-o", cfsopt,
851 				    fscache_object_p->i_backfs,
852 				    fscache_object_p->i_mntpt, NULL);
853 				break;
854 			default:
855 				(void) waitpid(child_pid, &stat_loc, WUNTRACED);
856 			}
857 
858 		}
859 
860 		/* get the root fid of the file system */
861 		xx = kmod_rootfid(kmod_object_p, &rootfid);
862 		if (xx) {
863 			dbug_print(("info", "could not mount back fs %s %d",
864 			    fscache_object_p->i_backfs, xx));
865 			continue;
866 		}
867 
868 		/* dummy up a fake kcred */
869 		(void) memset(&cr, 0, sizeof (cr));
870 
871 		/* try to get attrs on the root */
872 		xx = kmod_getattrfid(kmod_object_p, &rootfid, &cr, &va);
873 		if ((xx == ETIMEDOUT) || (xx == EIO)) {
874 			dbug_print(("info", "Bogus error %d", xx));
875 			continue;
876 		}
877 		break;
878 	}
879 	dbug_leave("fscache_server_alive");
880 }
881 
882 /*
883  *			fscache_pingserver
884  *
885  * Description:
886  *	Trys to ping the nfs server to see if it is alive.
887  * Arguments:
888  * Returns:
889  *	Returns 0 if it is alive, -1 if no answer.
890  * Preconditions:
891  */
892 
893 int
894 fscache_pingserver(cfsd_fscache_object_t *fscache_object_p)
895 {
896 
897 	static struct timeval TIMEOUT = { 25, 0 };
898 	CLIENT *clnt;
899 	enum clnt_stat retval;
900 	int ret = 0;
901 	char hostname[sizeof (fscache_object_p->i_backfs)];
902 	char *cptr;
903 
904 	dbug_enter("fscache_pingserver");
905 	dbug_precond(fscache_object_p);
906 
907 	strlcpy(hostname, fscache_object_p->i_backfs, sizeof (hostname));
908 	if (cptr = strchr(hostname, ':'))
909 		*cptr = '\0';
910 
911 	dbug_assert(cptr != NULL);
912 	dbug_print(("info", "remote host '%s' before clnt_create", hostname));
913 
914 	dbug_print(("info", "before clnt_create"));
915 	/* XXX this takes 75 seconds to time out */
916 	/* XXX should use lower level routines to reduce overhead */
917 	clnt = clnt_create(hostname, NFS_PROGRAM, NFS_VERSION, "udp");
918 	if (clnt == NULL) {
919 		/* XXX what if this fails other than TIMEDOUT */
920 		/* clnt_pcreateerror(hostname); */
921 		dbug_print(("info", "clnt_create failed"));
922 		ret = -1;
923 	} else {
924 		dbug_print(("info", "before null rpc"));
925 		/* XXX this takes 45 seconds to time out */
926 		retval = clnt_call(clnt, 0, xdr_void, NULL, xdr_void, NULL,
927 		    TIMEOUT);
928 		if (retval != RPC_SUCCESS) {
929 			/* clnt_perror(clnt, "null rpc call failed"); */
930 			dbug_print(("info", "null rpc call failed %d", retval));
931 			ret = -1;
932 		}
933 		clnt_destroy(clnt);
934 	}
935 	dbug_leave("fscache_pingserver");
936 	return (ret);
937 }
938 
939 /*
940  *			fscache_roll
941  *
942  * Description:
943  *	Rolls the contents of the log to the server.
944  * Arguments:
945  *	kmodp	interface to kernel functions
946  * Returns:
947  *	Returns 0 for success or ETIMEDOUT if a timeout error occurred.
948  * Preconditions:
949  *	precond(kmodp)
950  */
951 int
952 fscache_roll(cfsd_fscache_object_t *fscache_object_p,
953 	cfsd_kmod_object_t *kmod_object_p)
954 {
955 	int error = 0;
956 	cfsd_logelem_object_t *logelem_object_p;
957 	char namebuf[MAXPATHLEN];
958 	char backupfile[MAXPATHLEN];
959 	int xx;
960 	cfs_dlog_entry_t *entp;
961 	off_t next_offset;
962 	ulong_t curseq = 0;
963 	int eof = 0;
964 	char *xp;
965 	cfsd_logfile_object_t *logfile_object_p;
966 	cfsd_maptbl_object_t *maptbl_object_p;
967 
968 	dbug_enter("fscache_roll");
969 
970 	dbug_precond(fscache_object_p);
971 	dbug_precond(kmod_object_p);
972 
973 	/* map in the log file */
974 	logfile_object_p = cfsd_logfile_create();
975 
976 	snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
977 	    fscache_object_p->i_cachepath, fscache_object_p->i_name,
978 	    CACHEFS_DLOG_FILE);
979 	xx = logfile_setup(logfile_object_p, namebuf, CFS_DLOG_ENTRY_MAXSIZE);
980 	if (xx) {
981 		if (xx == ENOENT) {
982 			cfsd_logfile_destroy(logfile_object_p);
983 			dbug_leave("fscache_roll");
984 			return (0);
985 		}
986 		fscache_fsproblem(fscache_object_p, kmod_object_p);
987 		cfsd_logfile_destroy(logfile_object_p);
988 		dbug_leave("fscache_roll");
989 		return (0);
990 	}
991 
992 	fscache_lock(fscache_object_p);
993 	fscache_changes(fscache_object_p, 1);
994 	fscache_unlock(fscache_object_p);
995 
996 	/* create a hashed mapping table for changes to cids */
997 	maptbl_object_p = cfsd_maptbl_create();
998 	snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
999 	    fscache_object_p->i_cachepath, fscache_object_p->i_name,
1000 	    CACHEFS_DMAP_FILE);
1001 	xx = maptbl_setup(maptbl_object_p, namebuf);
1002 	if (xx) {
1003 		fscache_fsproblem(fscache_object_p, kmod_object_p);
1004 		cfsd_logfile_destroy(logfile_object_p);
1005 		cfsd_maptbl_destroy(maptbl_object_p);
1006 		dbug_leave("fscache_roll");
1007 		return (0);
1008 	}
1009 
1010 	/*
1011 	 * lock is not needed because they are only used when
1012 	 * rolling the log by fscache_roll and fscache_addagain
1013 	 */
1014 	fscache_object_p->i_again_offset = 0;
1015 	fscache_object_p->i_again_seq = 0;
1016 
1017 	/* Pass 1: collect all cid to fid mappings */
1018 	next_offset = LOGFILE_ENTRY_START;
1019 	for (;;) {
1020 		/* get a pointer to the next record */
1021 		xx = logfile_entry(logfile_object_p, next_offset, &entp);
1022 		if (xx == 1)
1023 			break;
1024 		if (xx == -1) {
1025 			fscache_fsproblem(fscache_object_p, kmod_object_p);
1026 			cfsd_logfile_destroy(logfile_object_p);
1027 			cfsd_maptbl_destroy(maptbl_object_p);
1028 			dbug_leave("fscache_roll");
1029 			return (0);
1030 		}
1031 		next_offset += entp->dl_len;
1032 
1033 		/* skip record if not valid */
1034 		if (entp->dl_valid != CFS_DLOG_VAL_COMMITTED)
1035 			continue;
1036 
1037 		/* create an object for the appropriate log type */
1038 		logelem_object_p = NULL;
1039 		switch (entp->dl_op) {
1040 		case CFS_DLOG_CREATE:
1041 		case CFS_DLOG_REMOVE:
1042 		case CFS_DLOG_LINK:
1043 		case CFS_DLOG_RENAME:
1044 		case CFS_DLOG_MKDIR:
1045 		case CFS_DLOG_RMDIR:
1046 		case CFS_DLOG_SYMLINK:
1047 		case CFS_DLOG_SETATTR:
1048 		case CFS_DLOG_SETSECATTR:
1049 		case CFS_DLOG_MODIFIED:
1050 		case CFS_DLOG_TRAILER:
1051 			break;
1052 
1053 		case CFS_DLOG_MAPFID:
1054 			dbug_print(("info", "mapfid"));
1055 			logelem_object_p = cfsd_logelem_mapfid_create(
1056 			    maptbl_object_p, logfile_object_p,
1057 			    kmod_object_p);
1058 			break;
1059 
1060 		default:
1061 			dbug_assert(0);
1062 			fscache_fsproblem(fscache_object_p, kmod_object_p);
1063 			break;
1064 		}
1065 
1066 		/* do not bother if ignoring the record */
1067 		if (logelem_object_p == NULL)
1068 			continue;
1069 
1070 		/* debuggging */
1071 		logelem_dump(logelem_object_p);
1072 
1073 		/* roll the entry */
1074 		xx = logelem_roll(logelem_object_p, (ulong_t *)NULL);
1075 		if (xx) {
1076 			fscache_fsproblem(fscache_object_p, kmod_object_p);
1077 			cfsd_logelem_destroy(logelem_object_p);
1078 			cfsd_maptbl_destroy(maptbl_object_p);
1079 			cfsd_logfile_destroy(logfile_object_p);
1080 			dbug_leave("fscache_roll");
1081 			return (0);
1082 		}
1083 
1084 		/* mark record as completed */
1085 		entp->dl_valid = CFS_DLOG_VAL_PROCESSED;
1086 		xx = logfile_sync(logfile_object_p);
1087 		if (xx) {
1088 			fscache_fsproblem(fscache_object_p, kmod_object_p);
1089 			cfsd_logelem_destroy(logelem_object_p);
1090 			cfsd_maptbl_destroy(maptbl_object_p);
1091 			cfsd_logfile_destroy(logfile_object_p);
1092 			dbug_leave("fscache_roll");
1093 			return (0);
1094 		}
1095 
1096 		/* destroy the object */
1097 		cfsd_logelem_destroy(logelem_object_p);
1098 	}
1099 
1100 	/* Pass 2: modify the back file system */
1101 	next_offset = LOGFILE_ENTRY_START;
1102 	for (;;) {
1103 		/* if we need the seq number of a deferred modify */
1104 		if (fscache_object_p->i_again_offset &&
1105 			(fscache_object_p->i_again_seq == 0)) {
1106 
1107 			/* get a pointer to the next record */
1108 			xx = logfile_entry(logfile_object_p,
1109 			    fscache_object_p->i_again_offset, &entp);
1110 			if (xx == 1)
1111 				break;
1112 			if (xx == -1) {
1113 				fscache_fsproblem(fscache_object_p,
1114 					kmod_object_p);
1115 				cfsd_logfile_destroy(logfile_object_p);
1116 				cfsd_maptbl_destroy(maptbl_object_p);
1117 				dbug_leave("fscache_roll");
1118 				return (0);
1119 			}
1120 			dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1121 			fscache_object_p->i_again_seq = entp->dl_seq;
1122 			dbug_assert(fscache_object_p->i_again_seq != 0);
1123 		}
1124 
1125 		/* get a pointer to the next record to process */
1126 		if (!eof) {
1127 			xx = logfile_entry(logfile_object_p, next_offset,
1128 			    &entp);
1129 			if (xx == 1) {
1130 				eof = 1;
1131 				curseq = ULONG_MAX;
1132 			} else if (xx) {
1133 				break;
1134 			} else {
1135 				curseq = entp->dl_seq;
1136 			}
1137 		}
1138 
1139 		/* if its time to process a deferred modify entry */
1140 		if (fscache_object_p->i_again_seq &&
1141 		    (eof || (fscache_object_p->i_again_seq < entp->dl_seq))) {
1142 			xx = logfile_entry(logfile_object_p,
1143 			    fscache_object_p->i_again_offset, &entp);
1144 			if (xx)
1145 				break;
1146 			dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1147 			curseq = entp->dl_seq;
1148 			fscache_object_p->i_again_offset =
1149 			    entp->dl_u.dl_modify.dl_next;
1150 			fscache_object_p->i_again_seq = 0;
1151 			entp->dl_u.dl_modify.dl_next = -1;
1152 		} else if (eof) {
1153 			xx = 0;
1154 			break;
1155 		}
1156 
1157 		/* else move the offset to the next record */
1158 		else {
1159 			next_offset += entp->dl_len;
1160 		}
1161 
1162 		/* skip record if not valid */
1163 		if (entp->dl_valid != CFS_DLOG_VAL_COMMITTED)
1164 			continue;
1165 
1166 		/* process the record */
1167 		xx = fscache_rollone(fscache_object_p, kmod_object_p,
1168 		    maptbl_object_p, logfile_object_p, curseq);
1169 		if (xx == ETIMEDOUT) {
1170 			/* timeout error, back to disconnected */
1171 			cfsd_maptbl_destroy(maptbl_object_p);
1172 			cfsd_logfile_destroy(logfile_object_p);
1173 			dbug_print(("info", "timeout error occurred"));
1174 			dbug_leave("fscache_roll");
1175 			return (xx);
1176 		} else if (xx == EIO) {
1177 			break;
1178 		} else if (xx == EAGAIN) {
1179 			continue;
1180 		} else if (xx) {
1181 			/* should never happen */
1182 			dbug_assert(0);
1183 			break;
1184 		} else {
1185 			/* mark record as completed */
1186 			entp->dl_valid = CFS_DLOG_VAL_PROCESSED;
1187 			xx = logfile_sync(logfile_object_p);
1188 			if (xx)
1189 				break;
1190 		}
1191 	}
1192 
1193 	/* if an unrecoverable error occurred */
1194 	if (xx) {
1195 		dbug_print(("error", "error processing log file"));
1196 		fscache_fsproblem(fscache_object_p, kmod_object_p);
1197 	}
1198 
1199 	/* dump stats about the hash table */
1200 	maptbl_dumpstats(maptbl_object_p);
1201 
1202 	/* dump stats about the log file */
1203 	logfile_dumpstats(logfile_object_p);
1204 
1205 	/* debugging hack, rename the log files */
1206 
1207 	if (snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
1208 	    fscache_object_p->i_cachepath, fscache_object_p->i_name,
1209 	    CACHEFS_DLOG_FILE) > ((sizeof (backupfile)) - (sizeof (".bak")))) {
1210 		dbug_print(("error", "unable to create backup dlog_file "
1211 		    "for %s, path name is too long", namebuf));
1212 	} else {
1213 		/*
1214 		 * No need to check return value from snprintf() as
1215 		 * the previous check should suffice.
1216 		 */
1217 		snprintf(backupfile, sizeof (backupfile), "%s.bak", namebuf);
1218 		if (rename(namebuf, backupfile) == -1) {
1219 			dbug_print(("error",
1220 			    "unable to create backup dlog_file"));
1221 		}
1222 	}
1223 
1224 	if (snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
1225 	    fscache_object_p->i_cachepath, fscache_object_p->i_name,
1226 	    CACHEFS_DMAP_FILE) > ((sizeof (backupfile)) - (sizeof (".bak")))) {
1227 		dbug_print(("error", "unable to create backup dmap_file "
1228 		    "for %s, path name is too long", namebuf));
1229 	} else {
1230 		/*
1231 		 * No need to check return value from snprintf() as
1232 		 * the previous check should suffice.
1233 		 */
1234 		snprintf(backupfile, sizeof (backupfile), "%s.bak", namebuf);
1235 		if (rename(namebuf, backupfile) == -1) {
1236 			dbug_print(("error",
1237 			    "unable to create backup dmap_file"));
1238 		}
1239 	}
1240 
1241 	/* delete the log file */
1242 	/* XXX */
1243 
1244 	cfsd_maptbl_destroy(maptbl_object_p);
1245 	cfsd_logfile_destroy(logfile_object_p);
1246 	dbug_leave("fscache_roll");
1247 	return (error);
1248 }
1249 
1250 /*
1251  *			fscache_rollone
1252  *
1253  * Description:
1254  * Arguments:
1255  *	kmodp
1256  *	tblp
1257  *	lfp
1258  * Returns:
1259  *	Returns ...
1260  * Preconditions:
1261  *	precond(kmodp)
1262  *	precond(tblp)
1263  *	precond(lfp)
1264  */
1265 int
1266 fscache_rollone(cfsd_fscache_object_t *fscache_object_p,
1267 	cfsd_kmod_object_t *kmod_object_p,
1268 	cfsd_maptbl_object_t *maptbl_object_p,
1269 	cfsd_logfile_object_t *logfile_object_p,
1270 	ulong_t seq)
1271 {
1272 	cfsd_logelem_object_t *logelem_object_p = NULL;
1273 	cfs_dlog_entry_t *entp;
1274 	int xx;
1275 	char *strp;
1276 
1277 	dbug_enter("fscache_rollone");
1278 
1279 	dbug_precond(fscache_object_p);
1280 	dbug_precond(kmod_object_p);
1281 	dbug_precond(maptbl_object_p);
1282 	dbug_precond(logfile_object_p);
1283 
1284 	entp = logfile_object_p->i_cur_entry;
1285 
1286 	/* create an object for the appropriate log type */
1287 	switch (entp->dl_op) {
1288 	case CFS_DLOG_CREATE:
1289 		dbug_print(("info", "create"));
1290 		logelem_object_p = cfsd_logelem_create_create(maptbl_object_p,
1291 		    logfile_object_p, kmod_object_p);
1292 		break;
1293 
1294 	case CFS_DLOG_REMOVE:
1295 		dbug_print(("info", "remove"));
1296 		logelem_object_p = cfsd_logelem_remove_create(maptbl_object_p,
1297 		    logfile_object_p, kmod_object_p);
1298 		break;
1299 
1300 	case CFS_DLOG_LINK:
1301 		dbug_print(("info", "link"));
1302 		logelem_object_p = cfsd_logelem_link_create(maptbl_object_p,
1303 		    logfile_object_p, kmod_object_p);
1304 		break;
1305 
1306 	case CFS_DLOG_RENAME:
1307 		dbug_print(("info", "rename"));
1308 		logelem_object_p = cfsd_logelem_rename_create(maptbl_object_p,
1309 		    logfile_object_p, kmod_object_p);
1310 		break;
1311 
1312 	case CFS_DLOG_MKDIR:
1313 		dbug_print(("info", "mkdir"));
1314 		logelem_object_p = cfsd_logelem_mkdir_create(maptbl_object_p,
1315 		    logfile_object_p, kmod_object_p);
1316 		break;
1317 
1318 	case CFS_DLOG_RMDIR:
1319 		dbug_print(("info", "rmdir"));
1320 		logelem_object_p = cfsd_logelem_rmdir_create(maptbl_object_p,
1321 		    logfile_object_p, kmod_object_p);
1322 		break;
1323 
1324 	case CFS_DLOG_SYMLINK:
1325 		dbug_print(("info", "symlink"));
1326 		logelem_object_p = cfsd_logelem_symlink_create(maptbl_object_p,
1327 		    logfile_object_p, kmod_object_p);
1328 		break;
1329 
1330 	case CFS_DLOG_SETATTR:
1331 		dbug_print(("info", "setattr"));
1332 		logelem_object_p = cfsd_logelem_setattr_create(maptbl_object_p,
1333 		    logfile_object_p, kmod_object_p);
1334 		break;
1335 
1336 	case CFS_DLOG_SETSECATTR:
1337 		dbug_print(("info", "setsecattr"));
1338 		logelem_object_p = cfsd_logelem_setsecattr_create(
1339 		    maptbl_object_p, logfile_object_p, kmod_object_p);
1340 		break;
1341 
1342 	case CFS_DLOG_MODIFIED:
1343 		dbug_print(("info", "modified"));
1344 		logelem_object_p = cfsd_logelem_modified_create(maptbl_object_p,
1345 		    logfile_object_p, kmod_object_p);
1346 		break;
1347 
1348 	case CFS_DLOG_MAPFID:
1349 		dbug_print(("info", "mapfid"));
1350 		break;
1351 
1352 	case CFS_DLOG_TRAILER:
1353 		dbug_print(("info", "trailer"));
1354 		break;
1355 
1356 	default:
1357 		dbug_assert(0);
1358 		dbug_leave("fscache_rollone");
1359 		return (EIO);
1360 	}
1361 
1362 	/* do not bother if ignoring the record */
1363 	if (logelem_object_p == NULL) {
1364 		dbug_print(("info", "record ignored"));
1365 		dbug_leave("fscache_rollone");
1366 		return (0);
1367 	}
1368 
1369 	/* XXX debugging */
1370 	logelem_dump(logelem_object_p);
1371 
1372 	/* roll the entry */
1373 	xx = logelem_roll(logelem_object_p, &seq);
1374 
1375 	strp = logelem_object_p->i_messagep;
1376 	if (strp) {
1377 		write(fscache_object_p->i_ofd, strp, strlen(strp));
1378 		dbug_print(("conflict", "%s", strp));
1379 	}
1380 
1381 	if (xx == EAGAIN) {
1382 		dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1383 		xx = fscache_addagain(fscache_object_p, logfile_object_p, seq);
1384 		if (xx == 0)
1385 			xx = EAGAIN;
1386 	}
1387 
1388 	/* destroy the object */
1389 	cfsd_logelem_destroy(logelem_object_p);
1390 
1391 	dbug_leave("fscache_rollone");
1392 	return (xx);
1393 }
1394 
1395 /*
1396  *			fscache_addagain
1397  *
1398  * Description:
1399  * Arguments:
1400  *	lfp
1401  * Returns:
1402  *	Returns ...
1403  * Preconditions:
1404  *	precond(lfp)
1405  */
1406 int
1407 fscache_addagain(cfsd_fscache_object_t *fscache_object_p,
1408 	cfsd_logfile_object_t *logfile_object_p,
1409 	ulong_t nseq)
1410 {
1411 	int xx;
1412 	cfs_dlog_entry_t *entp;
1413 	off_t noffset;
1414 	off_t prevoff = 0;
1415 	off_t toff;
1416 
1417 	dbug_enter("fscache_addagain");
1418 
1419 	dbug_precond(fscache_object_p);
1420 	dbug_precond(logfile_object_p);
1421 
1422 	entp = logfile_object_p->i_cur_entry;
1423 
1424 	noffset = logfile_object_p->i_cur_offset;
1425 
1426 	dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1427 	dbug_assert(nseq);
1428 
1429 	/* both set or both zero */
1430 	dbug_assert((!fscache_object_p->i_again_seq ^
1431 	    !fscache_object_p->i_again_offset) == 0);
1432 
1433 	entp->dl_seq = nseq;
1434 	/* simple case, first one on list */
1435 	if ((fscache_object_p->i_again_seq == 0) ||
1436 	    (nseq < fscache_object_p->i_again_seq)) {
1437 		entp->dl_u.dl_modify.dl_next = fscache_object_p->i_again_offset;
1438 		fscache_object_p->i_again_seq = nseq;
1439 		fscache_object_p->i_again_offset = noffset;
1440 		dbug_leave("fscache_addagain");
1441 		return (0);
1442 	}
1443 
1444 	/* Search until we find the element on the list prior to the */
1445 	/* insertion point. */
1446 	for (toff = fscache_object_p->i_again_offset; toff != 0;
1447 		toff = entp->dl_u.dl_modify.dl_next) {
1448 		/* get pointer to next element on the list */
1449 		xx = logfile_entry(logfile_object_p, toff, &entp);
1450 		if (xx) {
1451 			dbug_leave("fscache_addagain");
1452 			return (xx);
1453 		}
1454 		dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1455 
1456 		/* done if we found the element after the insertion point */
1457 		if (nseq < entp->dl_seq)
1458 			break;
1459 		prevoff = toff;
1460 	}
1461 	dbug_assert(prevoff);
1462 
1463 	/* get pointer to element prior to the insertion point */
1464 	xx = logfile_entry(logfile_object_p, prevoff, &entp);
1465 	if (xx) {
1466 		dbug_leave("fscache_addagain");
1467 		return (xx);
1468 	}
1469 	dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1470 	dbug_assert(entp->dl_u.dl_modify.dl_next == toff);
1471 
1472 	/* set element to point to our new element */
1473 	entp->dl_u.dl_modify.dl_next = noffset;
1474 
1475 	/* get pointer to our new element */
1476 	xx = logfile_entry(logfile_object_p, noffset, &entp);
1477 	if (xx) {
1478 		dbug_leave("fscache_addagain");
1479 		return (xx);
1480 	}
1481 	dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1482 
1483 	/* set it to point to next link or end of list */
1484 	entp->dl_u.dl_modify.dl_next = toff;
1485 
1486 	/* return success */
1487 	dbug_leave("fscache_addagain");
1488 	return (0);
1489 }
1490 
1491 /*
1492  *			fscache_fsproblem
1493  *
1494  * Description:
1495  * Arguments:
1496  *	kmodp
1497  * Returns:
1498  * Preconditions:
1499  *	precond(kmodp)
1500  */
1501 void
1502 fscache_fsproblem(cfsd_fscache_object_t *fscache_object_p,
1503 	cfsd_kmod_object_t *kmod_object_p)
1504 {
1505 #if 0
1506 	int xx;
1507 #endif
1508 
1509 	dbug_enter("fscache_fsproblem");
1510 
1511 	dbug_precond(fscache_object_p);
1512 	dbug_precond(kmod_object_p);
1513 
1514 #if 0
1515 	/* first try to put all modified files in lost+found */
1516 	xx = kmod_lostfoundall(kmod_object_p);
1517 	if (xx) {
1518 		/* if that failed, put file system in read-only mode */
1519 		kmod_rofs(kmod_object_p);
1520 #endif
1521 		fscache_lock(fscache_object_p);
1522 		fscache_object_p->i_disconnectable = 0;
1523 		fscache_object_p->i_modify++;
1524 		fscache_unlock(fscache_object_p);
1525 #if 0
1526 	}
1527 #endif
1528 	dbug_leave("fscache_fsproblem");
1529 }
1530 
1531 /*
1532  *			fscache_changes
1533  *
1534  * Description:
1535  *	Used to specify whether or not there are changes to roll to the
1536  *	server.
1537  * Arguments:
1538  *	tt
1539  * Returns:
1540  * Preconditions:
1541  */
1542 void
1543 fscache_changes(cfsd_fscache_object_t *fscache_object_p, int tt)
1544 {
1545 	dbug_enter("fscache_changes");
1546 	dbug_precond(fscache_object_p);
1547 	fscache_object_p->i_changes = tt;
1548 	fscache_object_p->i_modify++;
1549 	dbug_leave("fscache_changes");
1550 }
1551