11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/lockd/mon.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * The kernel statd client. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/types.h> 101da177e4SLinus Torvalds #include <linux/utsname.h> 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 131da177e4SLinus Torvalds #include <linux/sunrpc/svc.h> 141da177e4SLinus Torvalds #include <linux/lockd/lockd.h> 151da177e4SLinus Torvalds #include <linux/lockd/sm_inter.h> 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #define NLMDBG_FACILITY NLMDBG_MONITOR 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static struct rpc_clnt * nsm_create(void); 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static struct rpc_program nsm_program; 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /* 251da177e4SLinus Torvalds * Local NSM state 261da177e4SLinus Torvalds */ 27*460f5cacSOlaf Kirch int nsm_local_state; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* 301da177e4SLinus Torvalds * Common procedure for SM_MON/SM_UNMON calls 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds static int 339502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds struct rpc_clnt *clnt; 361da177e4SLinus Torvalds int status; 371da177e4SLinus Torvalds struct nsm_args args; 38dead28daSChuck Lever struct rpc_message msg = { 39dead28daSChuck Lever .rpc_argp = &args, 40dead28daSChuck Lever .rpc_resp = res, 41dead28daSChuck Lever }; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds clnt = nsm_create(); 441da177e4SLinus Torvalds if (IS_ERR(clnt)) { 451da177e4SLinus Torvalds status = PTR_ERR(clnt); 461da177e4SLinus Torvalds goto out; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 499502c522SOlaf Kirch memset(&args, 0, sizeof(args)); 50abd1f500SOlaf Kirch args.mon_name = nsm->sm_name; 519502c522SOlaf Kirch args.addr = nsm->sm_addr.sin_addr.s_addr; 521da177e4SLinus Torvalds args.prog = NLM_PROGRAM; 539502c522SOlaf Kirch args.vers = 3; 541da177e4SLinus Torvalds args.proc = NLMPROC_NSM_NOTIFY; 551da177e4SLinus Torvalds memset(res, 0, sizeof(*res)); 561da177e4SLinus Torvalds 57dead28daSChuck Lever msg.rpc_proc = &clnt->cl_procinfo[proc]; 58dead28daSChuck Lever status = rpc_call_sync(clnt, &msg, 0); 591da177e4SLinus Torvalds if (status < 0) 601da177e4SLinus Torvalds printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n", 611da177e4SLinus Torvalds status); 621da177e4SLinus Torvalds else 631da177e4SLinus Torvalds status = 0; 641da177e4SLinus Torvalds out: 651da177e4SLinus Torvalds return status; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* 691da177e4SLinus Torvalds * Set up monitoring of a remote host 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds int 721da177e4SLinus Torvalds nsm_monitor(struct nlm_host *host) 731da177e4SLinus Torvalds { 748dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 751da177e4SLinus Torvalds struct nsm_res res; 761da177e4SLinus Torvalds int status; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds dprintk("lockd: nsm_monitor(%s)\n", host->h_name); 798dead0dbSOlaf Kirch BUG_ON(nsm == NULL); 808dead0dbSOlaf Kirch 818dead0dbSOlaf Kirch if (nsm->sm_monitored) 82977faf39SOlaf Kirch return 0; 831da177e4SLinus Torvalds 849502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_MON, &res); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds if (status < 0 || res.status != 0) 871da177e4SLinus Torvalds printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); 881da177e4SLinus Torvalds else 898dead0dbSOlaf Kirch nsm->sm_monitored = 1; 901da177e4SLinus Torvalds return status; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* 941da177e4SLinus Torvalds * Cease to monitor remote host 951da177e4SLinus Torvalds */ 961da177e4SLinus Torvalds int 971da177e4SLinus Torvalds nsm_unmonitor(struct nlm_host *host) 981da177e4SLinus Torvalds { 998dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 1001da177e4SLinus Torvalds struct nsm_res res; 101977faf39SOlaf Kirch int status = 0; 1021da177e4SLinus Torvalds 1038dead0dbSOlaf Kirch if (nsm == NULL) 104977faf39SOlaf Kirch return 0; 1058dead0dbSOlaf Kirch host->h_nsmhandle = NULL; 1061da177e4SLinus Torvalds 1079502c522SOlaf Kirch if (atomic_read(&nsm->sm_count) == 1 1089502c522SOlaf Kirch && nsm->sm_monitored && !nsm->sm_sticky) { 1099502c522SOlaf Kirch dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); 1109502c522SOlaf Kirch 1119502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_UNMON, &res); 1121da177e4SLinus Torvalds if (status < 0) 1139502c522SOlaf Kirch printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 1149502c522SOlaf Kirch host->h_name); 1159502c522SOlaf Kirch else 1168dead0dbSOlaf Kirch nsm->sm_monitored = 0; 117977faf39SOlaf Kirch } 1188dead0dbSOlaf Kirch nsm_release(nsm); 1191da177e4SLinus Torvalds return status; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* 1231da177e4SLinus Torvalds * Create NSM client for the local host 1241da177e4SLinus Torvalds */ 1251da177e4SLinus Torvalds static struct rpc_clnt * 1261da177e4SLinus Torvalds nsm_create(void) 1271da177e4SLinus Torvalds { 128e1ec7892SChuck Lever struct sockaddr_in sin = { 129e1ec7892SChuck Lever .sin_family = AF_INET, 130e1ec7892SChuck Lever .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 131e1ec7892SChuck Lever .sin_port = 0, 132e1ec7892SChuck Lever }; 133e1ec7892SChuck Lever struct rpc_create_args args = { 134e1ec7892SChuck Lever .protocol = IPPROTO_UDP, 135e1ec7892SChuck Lever .address = (struct sockaddr *)&sin, 136e1ec7892SChuck Lever .addrsize = sizeof(sin), 137e1ec7892SChuck Lever .servername = "localhost", 138e1ec7892SChuck Lever .program = &nsm_program, 139e1ec7892SChuck Lever .version = SM_VERSION, 140e1ec7892SChuck Lever .authflavor = RPC_AUTH_NULL, 141e1ec7892SChuck Lever .flags = (RPC_CLNT_CREATE_ONESHOT), 142e1ec7892SChuck Lever }; 1431da177e4SLinus Torvalds 144e1ec7892SChuck Lever return rpc_create(&args); 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds /* 1481da177e4SLinus Torvalds * XDR functions for NSM. 1491da177e4SLinus Torvalds */ 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static u32 * 1521da177e4SLinus Torvalds xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) 1531da177e4SLinus Torvalds { 154abd1f500SOlaf Kirch char buffer[20], *name; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* 1571da177e4SLinus Torvalds * Use the dotted-quad IP address of the remote host as 1581da177e4SLinus Torvalds * identifier. Linux statd always looks up the canonical 1591da177e4SLinus Torvalds * hostname first for whatever remote hostname it receives, 1601da177e4SLinus Torvalds * so this works alright. 1611da177e4SLinus Torvalds */ 162abd1f500SOlaf Kirch if (nsm_use_hostnames) { 163abd1f500SOlaf Kirch name = argp->mon_name; 164abd1f500SOlaf Kirch } else { 1651da177e4SLinus Torvalds sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); 166abd1f500SOlaf Kirch name = buffer; 167abd1f500SOlaf Kirch } 168abd1f500SOlaf Kirch if (!(p = xdr_encode_string(p, name)) 169e9ff3990SSerge E. Hallyn || !(p = xdr_encode_string(p, utsname()->nodename))) 1701da177e4SLinus Torvalds return ERR_PTR(-EIO); 1711da177e4SLinus Torvalds *p++ = htonl(argp->prog); 1721da177e4SLinus Torvalds *p++ = htonl(argp->vers); 1731da177e4SLinus Torvalds *p++ = htonl(argp->proc); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds return p; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds static int 1791da177e4SLinus Torvalds xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) 1801da177e4SLinus Torvalds { 1811da177e4SLinus Torvalds p = xdr_encode_common(rqstp, p, argp); 1821da177e4SLinus Torvalds if (IS_ERR(p)) 1831da177e4SLinus Torvalds return PTR_ERR(p); 1849502c522SOlaf Kirch 1859502c522SOlaf Kirch /* Surprise - there may even be room for an IPv6 address now */ 1861da177e4SLinus Torvalds *p++ = argp->addr; 1879502c522SOlaf Kirch *p++ = 0; 1889502c522SOlaf Kirch *p++ = 0; 1891da177e4SLinus Torvalds *p++ = 0; 1901da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 1911da177e4SLinus Torvalds return 0; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds static int 1951da177e4SLinus Torvalds xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds p = xdr_encode_common(rqstp, p, argp); 1981da177e4SLinus Torvalds if (IS_ERR(p)) 1991da177e4SLinus Torvalds return PTR_ERR(p); 2001da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 2011da177e4SLinus Torvalds return 0; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds static int 2051da177e4SLinus Torvalds xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) 2061da177e4SLinus Torvalds { 2071da177e4SLinus Torvalds resp->status = ntohl(*p++); 2081da177e4SLinus Torvalds resp->state = ntohl(*p++); 2091da177e4SLinus Torvalds dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 2101da177e4SLinus Torvalds resp->status, resp->state); 2111da177e4SLinus Torvalds return 0; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds static int 2151da177e4SLinus Torvalds xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) 2161da177e4SLinus Torvalds { 2171da177e4SLinus Torvalds resp->state = ntohl(*p++); 2181da177e4SLinus Torvalds return 0; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2221da177e4SLinus Torvalds #define SM_my_id_sz (3+1+SM_my_name_sz) 2231da177e4SLinus Torvalds #define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz) 2241da177e4SLinus Torvalds #define SM_mon_sz (SM_mon_id_sz+4) 2251da177e4SLinus Torvalds #define SM_monres_sz 2 2261da177e4SLinus Torvalds #define SM_unmonres_sz 1 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds #ifndef MAX 2291da177e4SLinus Torvalds # define MAX(a, b) (((a) > (b))? (a) : (b)) 2301da177e4SLinus Torvalds #endif 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds static struct rpc_procinfo nsm_procedures[] = { 2331da177e4SLinus Torvalds [SM_MON] = { 2341da177e4SLinus Torvalds .p_proc = SM_MON, 2351da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_mon, 2361da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat_res, 2371da177e4SLinus Torvalds .p_bufsiz = MAX(SM_mon_sz, SM_monres_sz) << 2, 238cc0175c1SChuck Lever .p_statidx = SM_MON, 239cc0175c1SChuck Lever .p_name = "MONITOR", 2401da177e4SLinus Torvalds }, 2411da177e4SLinus Torvalds [SM_UNMON] = { 2421da177e4SLinus Torvalds .p_proc = SM_UNMON, 2431da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_unmon, 2441da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat, 2451da177e4SLinus Torvalds .p_bufsiz = MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, 246cc0175c1SChuck Lever .p_statidx = SM_UNMON, 247cc0175c1SChuck Lever .p_name = "UNMONITOR", 2481da177e4SLinus Torvalds }, 2491da177e4SLinus Torvalds }; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds static struct rpc_version nsm_version1 = { 2521da177e4SLinus Torvalds .number = 1, 253e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nsm_procedures), 2541da177e4SLinus Torvalds .procs = nsm_procedures 2551da177e4SLinus Torvalds }; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds static struct rpc_version * nsm_version[] = { 2581da177e4SLinus Torvalds [1] = &nsm_version1, 2591da177e4SLinus Torvalds }; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds static struct rpc_stat nsm_stats; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds static struct rpc_program nsm_program = { 2641da177e4SLinus Torvalds .name = "statd", 2651da177e4SLinus Torvalds .number = SM_PROGRAM, 266e8c96f8cSTobias Klauser .nrvers = ARRAY_SIZE(nsm_version), 2671da177e4SLinus Torvalds .version = nsm_version, 2681da177e4SLinus Torvalds .stats = &nsm_stats 2691da177e4SLinus Torvalds }; 270