6253 F_GETLK doesn't always return lock owner
[illumos-gate.git] / usr / src / cmd / fs.d / cachefs / cfsd / cfsd_svc.c
blobd7f6a7e220a0487eef1fa921a769ceb86c6805fa
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * RPC service routines.
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <rpc/rpc.h>
38 #include <rpc/pmap_clnt.h> /* for pmap_unset */
39 #include <string.h> /* strcmp */
40 #include <signal.h>
41 #include <unistd.h> /* setsid */
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <time.h>
45 #include <memory.h>
46 #include <stropts.h>
47 #include <netconfig.h>
48 #include <sys/resource.h> /* rlimit */
49 #include <thread.h>
50 #include <synch.h>
51 #include <mdbug/mdbug.h>
52 #include <common/cachefsd.h>
53 #include <sys/fs/cachefs_fs.h>
54 #include <sys/fs/cachefs_dlog.h>
55 #include <sys/fs/cachefs_ioctl.h>
56 #include "cfsd.h"
57 #include "cfsd_kmod.h"
58 #include "cfsd_maptbl.h"
59 #include "cfsd_logfile.h"
60 #include "cfsd_fscache.h"
61 #include "cfsd_cache.h"
62 #include "cfsd_all.h"
63 #include "cfsd_subr.h"
65 /* declared in cfsd_main.c */
66 extern cfsd_all_object_t *all_object_p;
69 * cachefsd_null_1_svc
71 * Description:
72 * Routine to process NULLPROC command, see /usr/include/rpc/clnt.h.
73 * Arguments:
74 * inp should be NULL
75 * outp should be NULL
76 * reqp svc_req info
77 * Returns:
78 * Always returns 1, e.g. returns success result.
79 * Preconditions:
80 * precond(reqp)
82 bool_t
83 cachefsd_null_1_svc(void *inp, void *outp, struct svc_req *reqp)
85 dbug_enter("cachefsd_null_1_svc");
86 dbug_precond(reqp);
88 dbug_assert(inp == NULL);
89 dbug_assert(outp == NULL);
91 dbug_leave("cachefsd_null_1_svc");
92 return (1);
96 * cachefsd_caches_1_svc
98 * Description:
99 * Returns list of caches on the system.
100 * Arguments:
101 * inp should be NULL
102 * outp should point to return object
103 * reqp svc_req info
104 * Returns:
105 * Returns 1 for success 0 if an error occurs.
106 * Preconditions:
107 * precond(reqp)
109 bool_t
110 cachefsd_caches_1_svc(void *inp,
111 cachefsd_caches_return *outp,
112 struct svc_req *reqp)
114 size_t cnt;
115 size_t index;
116 cfsd_cache_object_t *cache_object_p;
117 cachefsd_caches_id *headp, *idp;
119 dbug_enter("cachefsd_caches_1_svc");
120 dbug_precond(reqp);
122 dbug_assert(inp == NULL);
123 dbug_assert(outp);
125 if (inp || (outp == NULL)) {
126 dbug_leave("cachefsd_caches_1_svc");
127 return (0);
129 all_lock(all_object_p);
130 headp = NULL;
132 /* if there are any caches */
133 cnt = all_object_p->i_cachecount;
134 if (cnt) {
135 /* allocate space for each cache information */
136 headp = idp = cfsd_calloc(sizeof (cachefsd_caches_id) * cnt);
138 /* for each cache */
139 for (index = 0; index < cnt; index++, idp++) {
140 /* get the cache */
141 cache_object_p = all_cachelist_at(all_object_p, index);
142 dbug_assert(cache_object_p);
144 /* get the cache id and name */
145 idp->cci_cacheid = cache_object_p->i_cacheid;
146 idp->cci_name = subr_strdup(cache_object_p->i_cachedir);
150 /* fill in the return object */
151 outp->ccr_modify = all_object_p->i_modify;
152 outp->ccr_ids.ccr_ids_len = cnt;
153 outp->ccr_ids.ccr_ids_val = headp;
155 all_unlock(all_object_p);
157 dbug_leave("cachefsd_caches_1_svc");
158 return (1);
162 * cachefsd_cache_status_1_svc
164 * Description:
165 * Returns status about a particular cache.
166 * Arguments:
167 * inp should be ptr to cache id
168 * outp should be ptr to place to put cache status
169 * reqp svc_req info
170 * Returns:
171 * Returns 1 for success 0 if an error occurs.
172 * Preconditions:
173 * precond(reqp)
175 bool_t
176 cachefsd_cache_status_1_svc(int *inp, struct cachefsd_cache_status *outp,
177 struct svc_req *reqp)
179 cfsd_fscache_object_t *fscache_object_p = NULL;
180 size_t cnt, index;
181 cfsd_cache_object_t *cache_object_p;
182 cfsd_kmod_object_t *kmod_object_p;
183 cachefsio_getstats_t gs;
184 int xx;
186 dbug_enter("cachefsd_cache_status_1_svc");
187 dbug_precond(reqp);
189 dbug_assert(inp);
190 dbug_assert(outp);
192 if ((inp == NULL) || (outp == NULL)) {
193 dbug_leave("cachefsd_cache_status_1_svc");
194 return (0);
196 memset(outp, 0, sizeof (*outp));
198 /* find the requested cache */
199 all_lock(all_object_p);
200 cnt = all_object_p->i_cachecount;
201 for (index = 0; index < cnt; index++) {
202 /* get the cache */
203 cache_object_p = all_cachelist_at(all_object_p, index);
204 dbug_assert(cache_object_p);
206 /* if a match */
207 if (cache_object_p->i_cacheid == *inp) {
208 cache_lock(cache_object_p);
209 cache_object_p->i_refcnt++;
210 cache_unlock(cache_object_p);
211 break;
214 all_unlock(all_object_p);
216 /* if no match */
217 if (index >= cnt) {
218 dbug_leave("cachefsd_cache_status_1_svc");
219 return (1);
221 /* find a mounted file system in the cache */
222 cache_lock(cache_object_p);
223 cnt = cache_object_p->i_fscachecount;
224 for (index = 0; index < cnt; index++) {
225 /* get the fscache */
226 fscache_object_p = cache_fscachelist_at(cache_object_p, index);
227 dbug_assert(fscache_object_p);
229 /* mounted */
230 if (fscache_object_p->i_mounted) {
231 fscache_lock(fscache_object_p);
232 fscache_object_p->i_refcnt++;
233 fscache_unlock(fscache_object_p);
234 break;
236 fscache_object_p = NULL;
238 cache_unlock(cache_object_p);
240 outp->ccs_size = 0;
241 outp->ccs_lrusize = 0;
242 outp->ccs_packsize = 0;
243 outp->ccs_freesize = 0;
244 outp->ccs_lrutime = 0;
246 kmod_object_p = cfsd_kmod_create();
247 if (fscache_object_p) {
248 xx = kmod_setup(kmod_object_p, fscache_object_p->i_mntpt);
249 if (xx != 0) {
250 dbug_print(("err",
251 "setup of kmod interface failed %d", xx));
252 } else if ((xx = kmod_getstats(kmod_object_p, &gs)) != 0) {
253 dbug_print(("err", "getstat failed %d", xx));
254 } else {
255 outp->ccs_size = gs.gs_total;
256 outp->ccs_lrusize = gs.gs_gc + gs.gs_active;
257 outp->ccs_packsize = gs.gs_packed;
258 outp->ccs_freesize = gs.gs_free;
259 outp->ccs_lrutime = gs.gs_gctime;
261 fscache_lock(fscache_object_p);
262 fscache_object_p->i_refcnt--;
263 fscache_unlock(fscache_object_p);
266 cfsd_kmod_destroy(kmod_object_p);
268 outp->ccs_id = cache_object_p->i_cacheid;
269 outp->ccs_name = subr_strdup(cache_object_p->i_cachedir);
270 outp->ccs_modify = cache_object_p->i_modify;
271 cache_lock(cache_object_p);
272 cache_object_p->i_refcnt--;
273 cache_unlock(cache_object_p);
275 dbug_leave("cachefsd_cache_status_1_svc");
276 return (1);
280 * cachefsd_mounts_1_svc
282 * Description:
283 * Returns the list of file systems that are in the cache.
284 * Arguments:
285 * inp should be ptr to cache id
286 * outp should be ptr to place to put mounts
287 * reqp svc_req info
288 * Returns:
289 * Returns 1 for success 0 if an internal error occurs.
290 * Preconditions:
291 * precond(reqp)
293 bool_t
294 cachefsd_mounts_1_svc(int *inp, struct cachefsd_mount_returns *outp,
295 struct svc_req *reqp)
297 size_t cnt, index;
298 cfsd_cache_object_t *cache_object_p;
299 cfsd_fscache_object_t *fscache_object_p;
300 struct cachefsd_mount *headp, *idp;
302 dbug_enter("cachefsd_mounts_1_svc");
303 dbug_precond(reqp);
305 dbug_assert(inp);
306 dbug_assert(outp);
307 if ((inp == NULL) || (outp == NULL)) {
308 dbug_leave("cachefsd_mounts_1_svc");
309 return (0);
311 memset(outp, 0, sizeof (*outp));
313 /* find the requested cache */
314 all_lock(all_object_p);
315 cnt = all_object_p->i_cachecount;
316 for (index = 0; index < cnt; index++) {
317 /* get the cache */
318 cache_object_p = all_cachelist_at(all_object_p, index);
319 dbug_assert(cache_object_p);
321 /* if a match */
322 if (cache_object_p->i_cacheid == *inp) {
323 cache_lock(cache_object_p);
324 cache_object_p->i_refcnt++;
325 cache_unlock(cache_object_p);
326 break;
329 all_unlock(all_object_p);
331 /* if no match was found */
332 if (index >= cnt) {
333 outp->cmr_error = ENOENT;
334 dbug_leave("cachefsd_mounts_1_svc");
335 return (1);
338 cache_lock(cache_object_p);
339 headp = NULL;
341 /* if there are any fscaches */
342 cnt = cache_object_p->i_fscachecount;
343 if (cnt) {
344 /* allocate space for each fscache information */
345 headp = idp = cfsd_calloc(sizeof (cachefsd_mount) * cnt);
346 /* for each fscache */
347 for (index = 0; index < cnt; index++, idp++) {
348 /* get the fscache */
349 fscache_object_p =
350 cache_fscachelist_at(cache_object_p, index);
351 dbug_assert(fscache_object_p);
353 /* get the fscache id and name */
354 idp->cm_fsid = fscache_object_p->i_fscacheid;
355 idp->cm_name = subr_strdup(fscache_object_p->i_name);
359 /* fill in the return object */
360 outp->cmr_modify = cache_object_p->i_modify;
361 outp->cmr_error = 0;
362 outp->cmr_names.cmr_names_len = cnt;
363 outp->cmr_names.cmr_names_val = headp;
365 cache_object_p->i_refcnt--;
366 cache_unlock(cache_object_p);
368 dbug_leave("cachefsd_mounts_1_svc");
369 return (1);
373 * cachefsd_mount_stat_1_svc
375 * Description:
376 * Returns status information about a single file system
377 * in the cache.
378 * Arguments:
379 * inp should be which file system to get info for
380 * outp should be place to put mount info
381 * reqp svc_req info
382 * Returns:
383 * Returns 1 for success 0 if an error occurs.
384 * Preconditions:
385 * precond(reqp)
387 bool_t
388 cachefsd_mount_stat_1_svc(struct cachefsd_mount_stat_args *inp,
389 struct cachefsd_mount_stat *outp, struct svc_req *reqp)
391 size_t cnt, index;
392 cfsd_cache_object_t *cache_object_p;
393 cfsd_fscache_object_t *fscache_object_p;
394 char namebuf[MAXPATHLEN];
395 struct stat sinfo;
397 dbug_enter("cachefsd_mount_stat_1_svc");
398 dbug_precond(reqp);
400 dbug_assert(inp);
401 dbug_assert(outp);
402 if ((inp == NULL) || (outp == NULL)) {
403 dbug_leave("cachefsd_mount_stat_1_svc");
404 return (0);
406 memset(outp, 0, sizeof (*outp));
408 /* find the requested cache */
409 all_lock(all_object_p);
410 cnt = all_object_p->i_cachecount;
411 for (index = 0; index < cnt; index++) {
412 /* get the cache */
413 cache_object_p = all_cachelist_at(all_object_p, index);
414 dbug_assert(cache_object_p);
416 /* if a match */
417 if (cache_object_p->i_cacheid == inp->cma_cacheid) {
418 cache_lock(cache_object_p);
419 cache_object_p->i_refcnt++;
420 cache_unlock(cache_object_p);
421 break;
424 all_unlock(all_object_p);
426 /* if no match was found */
427 if (index >= cnt) {
428 dbug_leave("cachefsd_mount_stat_1_svc");
429 return (1);
432 /* find the requested fscache */
433 cache_lock(cache_object_p);
434 cnt = cache_object_p->i_fscachecount;
435 for (index = 0; index < cnt; index++) {
436 /* get the fscache */
437 fscache_object_p = cache_fscachelist_at(cache_object_p, index);
438 dbug_assert(fscache_object_p);
440 /* if a match */
441 if (fscache_object_p->i_fscacheid == inp->cma_fsid) {
442 fscache_lock(fscache_object_p);
443 fscache_object_p->i_refcnt++;
444 fscache_unlock(fscache_object_p);
445 break;
448 cache_unlock(cache_object_p);
450 /* if no match was found */
451 if (index >= cnt) {
452 cache_lock(cache_object_p);
453 cache_object_p->i_refcnt--;
454 cache_unlock(cache_object_p);
455 dbug_leave("cachefsd_mount_stat_1_svc");
456 return (1);
459 fscache_lock(fscache_object_p);
461 /* see if there are changes to roll to the server */
462 if ((fscache_object_p->i_connected == 0) &&
463 (fscache_object_p->i_changes == 0)) {
464 snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
465 cache_object_p->i_cachedir, fscache_object_p->i_name,
466 CACHEFS_DLOG_FILE);
467 if (stat(namebuf, &sinfo) == 0) {
468 fscache_changes(fscache_object_p, 1);
472 /* fill in the return object */
473 outp->cms_cacheid = cache_object_p->i_cacheid;
474 outp->cms_fsid = fscache_object_p->i_fscacheid;
475 outp->cms_name = subr_strdup(fscache_object_p->i_name);
476 outp->cms_backfs = subr_strdup(fscache_object_p->i_backfs);
477 outp->cms_mountpt = subr_strdup(fscache_object_p->i_mntpt);
478 outp->cms_backfstype = subr_strdup(fscache_object_p->i_backfstype);
479 outp->cms_writemode = NULL;
480 outp->cms_options = subr_strdup(fscache_object_p->i_cfsopt);
481 outp->cms_mounted = fscache_object_p->i_mounted;
482 outp->cms_connected = fscache_object_p->i_connected;
483 outp->cms_reconcile = fscache_object_p->i_reconcile;
484 outp->cms_changes = fscache_object_p->i_changes;
485 outp->cms_time_state = fscache_object_p->i_time_state;
486 outp->cms_mnttime = fscache_object_p->i_time_mnt;
487 outp->cms_modify = fscache_object_p->i_modify;
489 fscache_object_p->i_refcnt--;
490 fscache_unlock(fscache_object_p);
492 cache_lock(cache_object_p);
493 cache_object_p->i_refcnt--;
494 cache_unlock(cache_object_p);
496 dbug_leave("cachefsd_mount_stat_1_svc");
497 return (1);
501 * cachefsd_fs_mounted_1_svc
503 * Description:
504 * Sent by the mount command to indicate a new file system
505 * has been mounted
506 * Arguments:
507 * inp ptr to mount information
508 * outp should be null
509 * reqp svc_req info
510 * Returns:
511 * Returns 1 for success 0 if an internal error occurs.
512 * Preconditions:
513 * precond(inp)
515 bool_t
516 cachefsd_fs_mounted_1_svc(struct cachefsd_fs_mounted *inp, void *outp,
517 struct svc_req *reqp)
519 int error = 0;
521 dbug_enter("cachefsd_fs_mounted_1_svc");
522 dbug_precond(reqp);
524 dbug_assert(inp);
525 dbug_assert(outp == NULL);
526 if ((inp == NULL) || outp) {
527 dbug_leave("cachefsd_fs_mounted_1_svc");
528 return (0);
531 if (inp->mt_cachedir == NULL) {
532 dbug_print(("error", "cachedir is null"));
533 error = 1;
535 if (inp->mt_cacheid == NULL) {
536 dbug_print(("error", "cacheid is null"));
537 error = 1;
540 if (error == 0) {
541 dbug_print(("info", "Mounted in %s file system %s",
542 inp->mt_cachedir, inp->mt_cacheid));
543 subr_add_mount(all_object_p, inp->mt_cachedir, inp->mt_cacheid);
546 dbug_leave("cachefsd_fs_mounted_1_svc");
547 return (1);
551 * cachefsd_fs_unmounted_1_svc
553 * Description:
554 * Arguments:
555 * inp
556 * outp
557 * reqp
558 * Returns:
559 * Returns 1 for success 0 if an internal error occurs.
560 * Preconditions:
561 * precond(inp)
562 * precond(outp == NULL)
563 * precond(reqp)
565 bool_t
566 cachefsd_fs_unmounted_1_svc(struct cachefsd_fs_unmounted *inp, int *outp,
567 struct svc_req *reqp)
569 size_t cnt1, cnt2, index1, index2;
570 cfsd_cache_object_t *cache_object_p;
571 cfsd_fscache_object_t *fscache_object_p = NULL;
572 int found = 0;
573 int flag = 0;
575 dbug_enter("cachefsd_fs_unmounted_1_svc");
577 dbug_precond(inp);
578 dbug_precond(outp);
579 dbug_precond(reqp);
581 if ((inp == NULL) || (outp == NULL)) {
582 dbug_leave("cachefsd_fs_unmounted_1_svc");
583 return (0);
585 memset(outp, 0, sizeof (*outp));
587 if (inp->mntpt == NULL) {
588 dbug_print(("error", "mntpt is null"));
589 *outp = EIO;
590 dbug_leave("cachefsd_fs_unmounted_1_svc");
591 return (1);
594 /* for each cache */
595 all_lock(all_object_p);
596 cnt1 = all_object_p->i_cachecount;
597 for (index1 = 0; index1 < cnt1; index1++) {
598 /* get the cache */
599 cache_object_p = all_cachelist_at(all_object_p, index1);
600 dbug_assert(cache_object_p);
602 /* for each file system in this cache */
603 cache_lock(cache_object_p);
604 cnt2 = cache_object_p->i_fscachecount;
605 for (index2 = 0; index2 < cnt2; index2++) {
606 /* get the fscache */
607 fscache_object_p =
608 cache_fscachelist_at(cache_object_p, index2);
609 dbug_assert(fscache_object_p);
611 /* skip if not mounted */
612 if (fscache_object_p->i_mounted == 0)
613 continue;
615 /* if a match */
616 if (strcmp(fscache_object_p->i_mntpt,
617 inp->mntpt) == 0) {
618 fscache_lock(fscache_object_p);
619 fscache_object_p->i_refcnt++;
620 flag = inp->flag;
621 fscache_unlock(fscache_object_p);
622 found = 1;
623 break;
626 cache_unlock(cache_object_p);
627 if (found)
628 break;
629 fscache_object_p = NULL;
631 all_unlock(all_object_p);
633 /* if no match */
634 if (fscache_object_p == NULL) {
635 *outp = EIO;
636 } else {
637 *outp = fscache_unmount(fscache_object_p, flag);
639 fscache_lock(fscache_object_p);
640 fscache_object_p->i_refcnt--;
641 fscache_unlock(fscache_object_p);
643 dbug_leave("cachefsd_fs_unmounted_1_svc");
644 return (1);
648 * cachefsd_disconnection_1_svc
650 * Description:
651 * Arguments:
652 * inp
653 * outp
654 * reqp
655 * Returns:
656 * Returns 1 for success 0 if an internal error occurs.
657 * Preconditions:
658 * precond(inp)
659 * precond(outp)
660 * precond(reqp)
662 bool_t
663 cachefsd_disconnection_1_svc(struct cachefsd_disconnection_args *inp, int *outp,
664 struct svc_req *reqp)
666 size_t cnt1, cnt2, index1, index2;
667 cfsd_cache_object_t *cache_object_p;
668 cfsd_fscache_object_t *fscache_object_p = NULL;
669 int found = 0;
671 dbug_enter("cachefsd_disconnection_1_svc");
673 dbug_precond(inp);
674 dbug_precond(outp);
675 dbug_precond(reqp);
677 if ((inp == NULL) || (outp == NULL)) {
678 dbug_leave("cachefsd_disconnection_1_svc");
679 return (0);
681 memset(outp, 0, sizeof (*outp));
683 /* for each cache */
684 all_lock(all_object_p);
685 cnt1 = all_object_p->i_cachecount;
686 for (index1 = 0; index1 < cnt1; index1++) {
687 /* get the cache */
688 cache_object_p = all_cachelist_at(all_object_p, index1);
689 dbug_assert(cache_object_p);
691 /* for each file system in this cache */
692 cache_lock(cache_object_p);
693 cnt2 = cache_object_p->i_fscachecount;
694 for (index2 = 0; index2 < cnt2; index2++) {
695 /* get the fscache */
696 fscache_object_p =
697 cache_fscachelist_at(cache_object_p, index2);
698 dbug_assert(fscache_object_p);
700 /* if a match */
701 if (strcmp(fscache_object_p->i_mntpt, inp->cda_mntpt)
702 == 0) {
703 fscache_lock(fscache_object_p);
704 fscache_object_p->i_refcnt++;
705 fscache_unlock(fscache_object_p);
706 found = 1;
707 break;
710 cache_unlock(cache_object_p);
711 if (found)
712 break;
713 fscache_object_p = NULL;
715 all_unlock(all_object_p);
717 /* if no match */
718 if (fscache_object_p == NULL) {
719 *outp = 3;
720 } else {
721 *outp = fscache_simdisconnect(fscache_object_p,
722 inp->cda_disconnect);
724 fscache_lock(fscache_object_p);
725 fscache_object_p->i_refcnt--;
726 fscache_unlock(fscache_object_p);
728 dbug_leave("cachefsd_disconnection_1_svc");
729 return (1);
733 * cachefsdprog_1_freeresult
735 * Description:
736 * Arguments:
737 * transp
738 * xdr_result
739 * resultp
740 * Returns:
741 * Returns ...
742 * Preconditions:
743 * precond(transp)
746 cachefsdprog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
747 caddr_t resultp)
749 dbug_enter("cachefsdprog_1_freeresult");
751 dbug_precond(transp);
753 (void) xdr_free(xdr_result, resultp);
754 dbug_leave("cachefsdprog_1_freeresult");
755 return (1);