cfsd_svc.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h> /* for pmap_unset */
#include <string.h> /* strcmp */
#include <signal.h>
#include <unistd.h> /* setsid */
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <memory.h>
#include <stropts.h>
#include <netconfig.h>
#include <sys/resource.h> /* rlimit */
#include <thread.h>
#include <synch.h>
#include <mdbug/mdbug.h>
#include <common/cachefsd.h>
#include <sys/fs/cachefs_fs.h>
#include <sys/fs/cachefs_dlog.h>
#include <sys/fs/cachefs_ioctl.h>
#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);
}