/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * RPC service routines. */ #include #include #include #include #include #include /* for pmap_unset */ #include /* strcmp */ #include #include /* setsid */ #include #include #include #include #include #include #include /* rlimit */ #include #include #include #include #include #include #include #include "cfsd.h" #include "cfsd_kmod.h" #include "cfsd_maptbl.h" #include "cfsd_logfile.h" #include "cfsd_fscache.h" #include "cfsd_cache.h" #include "cfsd_all.h" #include "cfsd_subr.h" /* declared in cfsd_main.c */ extern cfsd_all_object_t *all_object_p; /* * cachefsd_null_1_svc * * Description: * Routine to process NULLPROC command, see /usr/include/rpc/clnt.h. * Arguments: * inp should be NULL * outp should be NULL * reqp svc_req info * Returns: * Always returns 1, e.g. returns success result. * Preconditions: * precond(reqp) */ bool_t cachefsd_null_1_svc(void *inp, void *outp, struct svc_req *reqp) { dbug_enter("cachefsd_null_1_svc"); dbug_precond(reqp); dbug_assert(inp == NULL); dbug_assert(outp == NULL); dbug_leave("cachefsd_null_1_svc"); return (1); } /* * cachefsd_caches_1_svc * * Description: * Returns list of caches on the system. * Arguments: * inp should be NULL * outp should point to return object * reqp svc_req info * Returns: * Returns 1 for success 0 if an error occurs. * Preconditions: * precond(reqp) */ bool_t cachefsd_caches_1_svc(void *inp, cachefsd_caches_return *outp, struct svc_req *reqp) { size_t cnt; size_t index; cfsd_cache_object_t *cache_object_p; cachefsd_caches_id *headp, *idp; dbug_enter("cachefsd_caches_1_svc"); dbug_precond(reqp); dbug_assert(inp == NULL); dbug_assert(outp); if (inp || (outp == NULL)) { dbug_leave("cachefsd_caches_1_svc"); return (0); } all_lock(all_object_p); headp = NULL; /* if there are any caches */ cnt = all_object_p->i_cachecount; if (cnt) { /* allocate space for each cache information */ headp = idp = cfsd_calloc(sizeof (cachefsd_caches_id) * cnt); /* for each cache */ for (index = 0; index < cnt; index++, idp++) { /* get the cache */ cache_object_p = all_cachelist_at(all_object_p, index); dbug_assert(cache_object_p); /* get the cache id and name */ idp->cci_cacheid = cache_object_p->i_cacheid; idp->cci_name = subr_strdup(cache_object_p->i_cachedir); } } /* fill in the return object */ outp->ccr_modify = all_object_p->i_modify; outp->ccr_ids.ccr_ids_len = cnt; outp->ccr_ids.ccr_ids_val = headp; all_unlock(all_object_p); dbug_leave("cachefsd_caches_1_svc"); return (1); } /* * cachefsd_cache_status_1_svc * * Description: * Returns status about a particular cache. * Arguments: * inp should be ptr to cache id * outp should be ptr to place to put cache status * reqp svc_req info * Returns: * Returns 1 for success 0 if an error occurs. * Preconditions: * precond(reqp) */ bool_t cachefsd_cache_status_1_svc(int *inp, struct cachefsd_cache_status *outp, struct svc_req *reqp) { cfsd_fscache_object_t *fscache_object_p = NULL; size_t cnt, index; cfsd_cache_object_t *cache_object_p; cfsd_kmod_object_t *kmod_object_p; cachefsio_getstats_t gs; int xx; dbug_enter("cachefsd_cache_status_1_svc"); dbug_precond(reqp); dbug_assert(inp); dbug_assert(outp); if ((inp == NULL) || (outp == NULL)) { dbug_leave("cachefsd_cache_status_1_svc"); return (0); } memset(outp, 0, sizeof (*outp)); /* find the requested cache */ all_lock(all_object_p); cnt = all_object_p->i_cachecount; for (index = 0; index < cnt; index++) { /* get the cache */ cache_object_p = all_cachelist_at(all_object_p, index); dbug_assert(cache_object_p); /* if a match */ if (cache_object_p->i_cacheid == *inp) { cache_lock(cache_object_p); cache_object_p->i_refcnt++; cache_unlock(cache_object_p); break; } } all_unlock(all_object_p); /* if no match */ if (index >= cnt) { dbug_leave("cachefsd_cache_status_1_svc"); return (1); } /* find a mounted file system in the cache */ cache_lock(cache_object_p); cnt = cache_object_p->i_fscachecount; for (index = 0; index < cnt; index++) { /* get the fscache */ fscache_object_p = cache_fscachelist_at(cache_object_p, index); dbug_assert(fscache_object_p); /* mounted */ if (fscache_object_p->i_mounted) { fscache_lock(fscache_object_p); fscache_object_p->i_refcnt++; fscache_unlock(fscache_object_p); break; } fscache_object_p = NULL; } cache_unlock(cache_object_p); outp->ccs_size = 0; outp->ccs_lrusize = 0; outp->ccs_packsize = 0; outp->ccs_freesize = 0; outp->ccs_lrutime = 0; kmod_object_p = cfsd_kmod_create(); if (fscache_object_p) { xx = kmod_setup(kmod_object_p, fscache_object_p->i_mntpt); if (xx != 0) { dbug_print(("err", "setup of kmod interface failed %d", xx)); } else if ((xx = kmod_getstats(kmod_object_p, &gs)) != 0) { dbug_print(("err", "getstat failed %d", xx)); } else { outp->ccs_size = gs.gs_total; outp->ccs_lrusize = gs.gs_gc + gs.gs_active; outp->ccs_packsize = gs.gs_packed; outp->ccs_freesize = gs.gs_free; outp->ccs_lrutime = gs.gs_gctime; fscache_lock(fscache_object_p); fscache_object_p->i_refcnt--; fscache_unlock(fscache_object_p); } } cfsd_kmod_destroy(kmod_object_p); outp->ccs_id = cache_object_p->i_cacheid; outp->ccs_name = subr_strdup(cache_object_p->i_cachedir); outp->ccs_modify = cache_object_p->i_modify; cache_lock(cache_object_p); cache_object_p->i_refcnt--; cache_unlock(cache_object_p); dbug_leave("cachefsd_cache_status_1_svc"); return (1); } /* * cachefsd_mounts_1_svc * * Description: * Returns the list of file systems that are in the cache. * Arguments: * inp should be ptr to cache id * outp should be ptr to place to put mounts * reqp svc_req info * Returns: * Returns 1 for success 0 if an internal error occurs. * Preconditions: * precond(reqp) */ bool_t cachefsd_mounts_1_svc(int *inp, struct cachefsd_mount_returns *outp, struct svc_req *reqp) { size_t cnt, index; cfsd_cache_object_t *cache_object_p; cfsd_fscache_object_t *fscache_object_p; struct cachefsd_mount *headp, *idp; dbug_enter("cachefsd_mounts_1_svc"); dbug_precond(reqp); dbug_assert(inp); dbug_assert(outp); if ((inp == NULL) || (outp == NULL)) { dbug_leave("cachefsd_mounts_1_svc"); return (0); } memset(outp, 0, sizeof (*outp)); /* find the requested cache */ all_lock(all_object_p); cnt = all_object_p->i_cachecount; for (index = 0; index < cnt; index++) { /* get the cache */ cache_object_p = all_cachelist_at(all_object_p, index); dbug_assert(cache_object_p); /* if a match */ if (cache_object_p->i_cacheid == *inp) { cache_lock(cache_object_p); cache_object_p->i_refcnt++; cache_unlock(cache_object_p); break; } } all_unlock(all_object_p); /* if no match was found */ if (index >= cnt) { outp->cmr_error = ENOENT; dbug_leave("cachefsd_mounts_1_svc"); return (1); } cache_lock(cache_object_p); headp = NULL; /* if there are any fscaches */ cnt = cache_object_p->i_fscachecount; if (cnt) { /* allocate space for each fscache information */ headp = idp = cfsd_calloc(sizeof (cachefsd_mount) * cnt); /* for each fscache */ for (index = 0; index < cnt; index++, idp++) { /* get the fscache */ fscache_object_p = cache_fscachelist_at(cache_object_p, index); dbug_assert(fscache_object_p); /* get the fscache id and name */ idp->cm_fsid = fscache_object_p->i_fscacheid; idp->cm_name = subr_strdup(fscache_object_p->i_name); } } /* fill in the return object */ outp->cmr_modify = cache_object_p->i_modify; outp->cmr_error = 0; outp->cmr_names.cmr_names_len = cnt; outp->cmr_names.cmr_names_val = headp; cache_object_p->i_refcnt--; cache_unlock(cache_object_p); dbug_leave("cachefsd_mounts_1_svc"); return (1); } /* * cachefsd_mount_stat_1_svc * * Description: * Returns status information about a single file system * in the cache. * Arguments: * inp should be which file system to get info for * outp should be place to put mount info * reqp svc_req info * Returns: * Returns 1 for success 0 if an error occurs. * Preconditions: * precond(reqp) */ bool_t cachefsd_mount_stat_1_svc(struct cachefsd_mount_stat_args *inp, struct cachefsd_mount_stat *outp, struct svc_req *reqp) { size_t cnt, index; cfsd_cache_object_t *cache_object_p; cfsd_fscache_object_t *fscache_object_p; char namebuf[MAXPATHLEN]; struct stat sinfo; dbug_enter("cachefsd_mount_stat_1_svc"); dbug_precond(reqp); dbug_assert(inp); dbug_assert(outp); if ((inp == NULL) || (outp == NULL)) { dbug_leave("cachefsd_mount_stat_1_svc"); return (0); } memset(outp, 0, sizeof (*outp)); /* find the requested cache */ all_lock(all_object_p); cnt = all_object_p->i_cachecount; for (index = 0; index < cnt; index++) { /* get the cache */ cache_object_p = all_cachelist_at(all_object_p, index); dbug_assert(cache_object_p); /* if a match */ if (cache_object_p->i_cacheid == inp->cma_cacheid) { cache_lock(cache_object_p); cache_object_p->i_refcnt++; cache_unlock(cache_object_p); break; } } all_unlock(all_object_p); /* if no match was found */ if (index >= cnt) { dbug_leave("cachefsd_mount_stat_1_svc"); return (1); } /* find the requested fscache */ cache_lock(cache_object_p); cnt = cache_object_p->i_fscachecount; for (index = 0; index < cnt; index++) { /* get the fscache */ fscache_object_p = cache_fscachelist_at(cache_object_p, index); dbug_assert(fscache_object_p); /* if a match */ if (fscache_object_p->i_fscacheid == inp->cma_fsid) { fscache_lock(fscache_object_p); fscache_object_p->i_refcnt++; fscache_unlock(fscache_object_p); break; } } cache_unlock(cache_object_p); /* if no match was found */ if (index >= cnt) { cache_lock(cache_object_p); cache_object_p->i_refcnt--; cache_unlock(cache_object_p); dbug_leave("cachefsd_mount_stat_1_svc"); return (1); } fscache_lock(fscache_object_p); /* see if there are changes to roll to the server */ if ((fscache_object_p->i_connected == 0) && (fscache_object_p->i_changes == 0)) { snprintf(namebuf, sizeof (namebuf), "%s/%s/%s", cache_object_p->i_cachedir, fscache_object_p->i_name, CACHEFS_DLOG_FILE); if (stat(namebuf, &sinfo) == 0) { fscache_changes(fscache_object_p, 1); } } /* fill in the return object */ outp->cms_cacheid = cache_object_p->i_cacheid; outp->cms_fsid = fscache_object_p->i_fscacheid; outp->cms_name = subr_strdup(fscache_object_p->i_name); outp->cms_backfs = subr_strdup(fscache_object_p->i_backfs); outp->cms_mountpt = subr_strdup(fscache_object_p->i_mntpt); outp->cms_backfstype = subr_strdup(fscache_object_p->i_backfstype); outp->cms_writemode = NULL; outp->cms_options = subr_strdup(fscache_object_p->i_cfsopt); outp->cms_mounted = fscache_object_p->i_mounted; outp->cms_connected = fscache_object_p->i_connected; outp->cms_reconcile = fscache_object_p->i_reconcile; outp->cms_changes = fscache_object_p->i_changes; outp->cms_time_state = fscache_object_p->i_time_state; outp->cms_mnttime = fscache_object_p->i_time_mnt; outp->cms_modify = fscache_object_p->i_modify; fscache_object_p->i_refcnt--; fscache_unlock(fscache_object_p); cache_lock(cache_object_p); cache_object_p->i_refcnt--; cache_unlock(cache_object_p); dbug_leave("cachefsd_mount_stat_1_svc"); return (1); } /* * cachefsd_fs_mounted_1_svc * * Description: * Sent by the mount command to indicate a new file system * has been mounted * Arguments: * inp ptr to mount information * outp should be null * reqp svc_req info * Returns: * Returns 1 for success 0 if an internal error occurs. * Preconditions: * precond(inp) */ bool_t cachefsd_fs_mounted_1_svc(struct cachefsd_fs_mounted *inp, void *outp, struct svc_req *reqp) { int error = 0; dbug_enter("cachefsd_fs_mounted_1_svc"); dbug_precond(reqp); dbug_assert(inp); dbug_assert(outp == NULL); if ((inp == NULL) || outp) { dbug_leave("cachefsd_fs_mounted_1_svc"); return (0); } if (inp->mt_cachedir == NULL) { dbug_print(("error", "cachedir is null")); error = 1; } if (inp->mt_cacheid == NULL) { dbug_print(("error", "cacheid is null")); error = 1; } if (error == 0) { dbug_print(("info", "Mounted in %s file system %s", inp->mt_cachedir, inp->mt_cacheid)); subr_add_mount(all_object_p, inp->mt_cachedir, inp->mt_cacheid); } dbug_leave("cachefsd_fs_mounted_1_svc"); return (1); } /* * cachefsd_fs_unmounted_1_svc * * Description: * Arguments: * inp * outp * reqp * Returns: * Returns 1 for success 0 if an internal error occurs. * Preconditions: * precond(inp) * precond(outp == NULL) * precond(reqp) */ bool_t cachefsd_fs_unmounted_1_svc(struct cachefsd_fs_unmounted *inp, int *outp, struct svc_req *reqp) { size_t cnt1, cnt2, index1, index2; cfsd_cache_object_t *cache_object_p; cfsd_fscache_object_t *fscache_object_p = NULL; int found = 0; int flag = 0; dbug_enter("cachefsd_fs_unmounted_1_svc"); dbug_precond(inp); dbug_precond(outp); dbug_precond(reqp); if ((inp == NULL) || (outp == NULL)) { dbug_leave("cachefsd_fs_unmounted_1_svc"); return (0); } memset(outp, 0, sizeof (*outp)); if (inp->mntpt == NULL) { dbug_print(("error", "mntpt is null")); *outp = EIO; dbug_leave("cachefsd_fs_unmounted_1_svc"); return (1); } /* for each cache */ all_lock(all_object_p); cnt1 = all_object_p->i_cachecount; for (index1 = 0; index1 < cnt1; index1++) { /* get the cache */ cache_object_p = all_cachelist_at(all_object_p, index1); dbug_assert(cache_object_p); /* for each file system in this cache */ cache_lock(cache_object_p); cnt2 = cache_object_p->i_fscachecount; for (index2 = 0; index2 < cnt2; index2++) { /* get the fscache */ fscache_object_p = cache_fscachelist_at(cache_object_p, index2); dbug_assert(fscache_object_p); /* skip if not mounted */ if (fscache_object_p->i_mounted == 0) continue; /* if a match */ if (strcmp(fscache_object_p->i_mntpt, inp->mntpt) == 0) { fscache_lock(fscache_object_p); fscache_object_p->i_refcnt++; flag = inp->flag; fscache_unlock(fscache_object_p); found = 1; break; } } cache_unlock(cache_object_p); if (found) break; fscache_object_p = NULL; } all_unlock(all_object_p); /* if no match */ if (fscache_object_p == NULL) { *outp = EIO; } else { *outp = fscache_unmount(fscache_object_p, flag); fscache_lock(fscache_object_p); fscache_object_p->i_refcnt--; fscache_unlock(fscache_object_p); } dbug_leave("cachefsd_fs_unmounted_1_svc"); return (1); } /* * cachefsd_disconnection_1_svc * * Description: * Arguments: * inp * outp * reqp * Returns: * Returns 1 for success 0 if an internal error occurs. * Preconditions: * precond(inp) * precond(outp) * precond(reqp) */ bool_t cachefsd_disconnection_1_svc(struct cachefsd_disconnection_args *inp, int *outp, struct svc_req *reqp) { size_t cnt1, cnt2, index1, index2; cfsd_cache_object_t *cache_object_p; cfsd_fscache_object_t *fscache_object_p = NULL; int found = 0; dbug_enter("cachefsd_disconnection_1_svc"); dbug_precond(inp); dbug_precond(outp); dbug_precond(reqp); if ((inp == NULL) || (outp == NULL)) { dbug_leave("cachefsd_disconnection_1_svc"); return (0); } memset(outp, 0, sizeof (*outp)); /* for each cache */ all_lock(all_object_p); cnt1 = all_object_p->i_cachecount; for (index1 = 0; index1 < cnt1; index1++) { /* get the cache */ cache_object_p = all_cachelist_at(all_object_p, index1); dbug_assert(cache_object_p); /* for each file system in this cache */ cache_lock(cache_object_p); cnt2 = cache_object_p->i_fscachecount; for (index2 = 0; index2 < cnt2; index2++) { /* get the fscache */ fscache_object_p = cache_fscachelist_at(cache_object_p, index2); dbug_assert(fscache_object_p); /* if a match */ if (strcmp(fscache_object_p->i_mntpt, inp->cda_mntpt) == 0) { fscache_lock(fscache_object_p); fscache_object_p->i_refcnt++; fscache_unlock(fscache_object_p); found = 1; break; } } cache_unlock(cache_object_p); if (found) break; fscache_object_p = NULL; } all_unlock(all_object_p); /* if no match */ if (fscache_object_p == NULL) { *outp = 3; } else { *outp = fscache_simdisconnect(fscache_object_p, inp->cda_disconnect); fscache_lock(fscache_object_p); fscache_object_p->i_refcnt--; fscache_unlock(fscache_object_p); } dbug_leave("cachefsd_disconnection_1_svc"); return (1); } /* * cachefsdprog_1_freeresult * * Description: * Arguments: * transp * xdr_result * resultp * Returns: * Returns ... * Preconditions: * precond(transp) */ int cachefsdprog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t resultp) { dbug_enter("cachefsdprog_1_freeresult"); dbug_precond(transp); (void) xdr_free(xdr_result, resultp); dbug_leave("cachefsdprog_1_freeresult"); return (1); }