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> 130896a725S\"Talpey, Thomas\ #include <linux/sunrpc/xprtsock.h> 141da177e4SLinus Torvalds #include <linux/sunrpc/svc.h> 151da177e4SLinus Torvalds #include <linux/lockd/lockd.h> 161da177e4SLinus Torvalds #include <linux/lockd/sm_inter.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #define NLMDBG_FACILITY NLMDBG_MONITOR 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds static struct rpc_clnt * nsm_create(void); 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds static struct rpc_program nsm_program; 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds /* 261da177e4SLinus Torvalds * Local NSM state 271da177e4SLinus Torvalds */ 28460f5cacSOlaf Kirch int nsm_local_state; 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * Common procedure for SM_MON/SM_UNMON calls 321da177e4SLinus Torvalds */ 331da177e4SLinus Torvalds static int 349502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 351da177e4SLinus Torvalds { 361da177e4SLinus Torvalds struct rpc_clnt *clnt; 371da177e4SLinus Torvalds int status; 38a4846750SChuck Lever struct nsm_args args = { 39a4846750SChuck Lever .addr = nsm_addr_in(nsm)->sin_addr.s_addr, 40a4846750SChuck Lever .prog = NLM_PROGRAM, 41a4846750SChuck Lever .vers = 3, 42a4846750SChuck Lever .proc = NLMPROC_NSM_NOTIFY, 4329ed1407SChuck Lever .mon_name = nsm->sm_mon_name, 44a4846750SChuck Lever }; 45dead28daSChuck Lever struct rpc_message msg = { 46dead28daSChuck Lever .rpc_argp = &args, 47dead28daSChuck Lever .rpc_resp = res, 48dead28daSChuck Lever }; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds clnt = nsm_create(); 511da177e4SLinus Torvalds if (IS_ERR(clnt)) { 521da177e4SLinus Torvalds status = PTR_ERR(clnt); 535acf4315SChuck Lever dprintk("lockd: failed to create NSM upcall transport, " 545acf4315SChuck Lever "status=%d\n", status); 551da177e4SLinus Torvalds goto out; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds memset(res, 0, sizeof(*res)); 591da177e4SLinus Torvalds 60dead28daSChuck Lever msg.rpc_proc = &clnt->cl_procinfo[proc]; 61dead28daSChuck Lever status = rpc_call_sync(clnt, &msg, 0); 621da177e4SLinus Torvalds if (status < 0) 635acf4315SChuck Lever dprintk("lockd: NSM upcall RPC failed, status=%d\n", 641da177e4SLinus Torvalds status); 651da177e4SLinus Torvalds else 661da177e4SLinus Torvalds status = 0; 6790c5755fSTrond Myklebust rpc_shutdown_client(clnt); 681da177e4SLinus Torvalds out: 691da177e4SLinus Torvalds return status; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721e49323cSChuck Lever /** 731e49323cSChuck Lever * nsm_monitor - Notify a peer in case we reboot 741e49323cSChuck Lever * @host: pointer to nlm_host of peer to notify 751e49323cSChuck Lever * 761e49323cSChuck Lever * If this peer is not already monitored, this function sends an 771e49323cSChuck Lever * upcall to the local rpc.statd to record the name/address of 781e49323cSChuck Lever * the peer to notify in case we reboot. 791e49323cSChuck Lever * 801e49323cSChuck Lever * Returns zero if the peer is monitored by the local rpc.statd; 811e49323cSChuck Lever * otherwise a negative errno value is returned. 821da177e4SLinus Torvalds */ 831e49323cSChuck Lever int nsm_monitor(const struct nlm_host *host) 841da177e4SLinus Torvalds { 858dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 861da177e4SLinus Torvalds struct nsm_res res; 871da177e4SLinus Torvalds int status; 881da177e4SLinus Torvalds 899fee4902SChuck Lever dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); 908dead0dbSOlaf Kirch 918dead0dbSOlaf Kirch if (nsm->sm_monitored) 92977faf39SOlaf Kirch return 0; 931da177e4SLinus Torvalds 9429ed1407SChuck Lever /* 9529ed1407SChuck Lever * Choose whether to record the caller_name or IP address of 9629ed1407SChuck Lever * this peer in the local rpc.statd's database. 9729ed1407SChuck Lever */ 9829ed1407SChuck Lever nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; 9929ed1407SChuck Lever 1009502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_MON, &res); 1015d254b11SChuck Lever if (res.status != 0) 1025d254b11SChuck Lever status = -EIO; 1035d254b11SChuck Lever if (status < 0) 1049fee4902SChuck Lever printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); 1051da177e4SLinus Torvalds else 1068dead0dbSOlaf Kirch nsm->sm_monitored = 1; 1071da177e4SLinus Torvalds return status; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 110356c3eb4SChuck Lever /** 111356c3eb4SChuck Lever * nsm_unmonitor - Unregister peer notification 112356c3eb4SChuck Lever * @host: pointer to nlm_host of peer to stop monitoring 113356c3eb4SChuck Lever * 114356c3eb4SChuck Lever * If this peer is monitored, this function sends an upcall to 115356c3eb4SChuck Lever * tell the local rpc.statd not to send this peer a notification 116356c3eb4SChuck Lever * when we reboot. 1171da177e4SLinus Torvalds */ 118356c3eb4SChuck Lever void nsm_unmonitor(const struct nlm_host *host) 1191da177e4SLinus Torvalds { 1208dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 1211da177e4SLinus Torvalds struct nsm_res res; 122356c3eb4SChuck Lever int status; 1231da177e4SLinus Torvalds 1249502c522SOlaf Kirch if (atomic_read(&nsm->sm_count) == 1 1259502c522SOlaf Kirch && nsm->sm_monitored && !nsm->sm_sticky) { 1269fee4902SChuck Lever dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); 1279502c522SOlaf Kirch 1289502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_UNMON, &res); 129*0c7aef45SChuck Lever if (res.status != 0) 130*0c7aef45SChuck Lever status = -EIO; 1311da177e4SLinus Torvalds if (status < 0) 1329502c522SOlaf Kirch printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 1339fee4902SChuck Lever nsm->sm_name); 1349502c522SOlaf Kirch else 1358dead0dbSOlaf Kirch nsm->sm_monitored = 0; 136977faf39SOlaf Kirch } 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* 1401da177e4SLinus Torvalds * Create NSM client for the local host 1411da177e4SLinus Torvalds */ 1421da177e4SLinus Torvalds static struct rpc_clnt * 1431da177e4SLinus Torvalds nsm_create(void) 1441da177e4SLinus Torvalds { 145e1ec7892SChuck Lever struct sockaddr_in sin = { 146e1ec7892SChuck Lever .sin_family = AF_INET, 147e1ec7892SChuck Lever .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 148e1ec7892SChuck Lever .sin_port = 0, 149e1ec7892SChuck Lever }; 150e1ec7892SChuck Lever struct rpc_create_args args = { 1510896a725S\"Talpey, Thomas\ .protocol = XPRT_TRANSPORT_UDP, 152e1ec7892SChuck Lever .address = (struct sockaddr *)&sin, 153e1ec7892SChuck Lever .addrsize = sizeof(sin), 154e1ec7892SChuck Lever .servername = "localhost", 155e1ec7892SChuck Lever .program = &nsm_program, 156e1ec7892SChuck Lever .version = SM_VERSION, 157e1ec7892SChuck Lever .authflavor = RPC_AUTH_NULL, 158e1ec7892SChuck Lever }; 1591da177e4SLinus Torvalds 160e1ec7892SChuck Lever return rpc_create(&args); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds /* 1641da177e4SLinus Torvalds * XDR functions for NSM. 1652ca7754dSChuck Lever * 1662ca7754dSChuck Lever * See http://www.opengroup.org/ for details on the Network 1672ca7754dSChuck Lever * Status Monitor wire protocol. 1681da177e4SLinus Torvalds */ 1691da177e4SLinus Torvalds 170099bd05fSChuck Lever static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) 171099bd05fSChuck Lever { 172099bd05fSChuck Lever size_t len = strlen(string); 173099bd05fSChuck Lever 174099bd05fSChuck Lever if (len > SM_MAXSTRLEN) 175099bd05fSChuck Lever len = SM_MAXSTRLEN; 176099bd05fSChuck Lever return xdr_encode_opaque(p, string, len); 177099bd05fSChuck Lever } 178099bd05fSChuck Lever 17949695174SChuck Lever /* 18049695174SChuck Lever * "mon_name" specifies the host to be monitored. 18149695174SChuck Lever */ 18249695174SChuck Lever static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) 18349695174SChuck Lever { 18429ed1407SChuck Lever return xdr_encode_nsm_string(p, argp->mon_name); 18549695174SChuck Lever } 18649695174SChuck Lever 187850c95fdSChuck Lever /* 188850c95fdSChuck Lever * The "my_id" argument specifies the hostname and RPC procedure 189850c95fdSChuck Lever * to be called when the status manager receives notification 190850c95fdSChuck Lever * (via the SM_NOTIFY call) that the state of host "mon_name" 191850c95fdSChuck Lever * has changed. 192850c95fdSChuck Lever */ 193850c95fdSChuck Lever static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) 194850c95fdSChuck Lever { 195850c95fdSChuck Lever p = xdr_encode_nsm_string(p, utsname()->nodename); 196850c95fdSChuck Lever if (!p) 197850c95fdSChuck Lever return ERR_PTR(-EIO); 198850c95fdSChuck Lever 199850c95fdSChuck Lever *p++ = htonl(argp->prog); 200850c95fdSChuck Lever *p++ = htonl(argp->vers); 201850c95fdSChuck Lever *p++ = htonl(argp->proc); 202850c95fdSChuck Lever 203850c95fdSChuck Lever return p; 204850c95fdSChuck Lever } 205850c95fdSChuck Lever 206ea72a7f1SChuck Lever /* 207ea72a7f1SChuck Lever * The "mon_id" argument specifies the non-private arguments 208ea72a7f1SChuck Lever * of an SM_MON or SM_UNMON call. 209ea72a7f1SChuck Lever */ 210ea72a7f1SChuck Lever static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) 211ea72a7f1SChuck Lever { 212ea72a7f1SChuck Lever p = xdr_encode_mon_name(p, argp); 213ea72a7f1SChuck Lever if (!p) 214ea72a7f1SChuck Lever return ERR_PTR(-EIO); 215ea72a7f1SChuck Lever 216ea72a7f1SChuck Lever return xdr_encode_my_id(p, argp); 217ea72a7f1SChuck Lever } 218ea72a7f1SChuck Lever 2190490a54aSChuck Lever /* 2200490a54aSChuck Lever * The "priv" argument may contain private information required 2210490a54aSChuck Lever * by the SM_MON call. This information will be supplied in the 2220490a54aSChuck Lever * SM_NOTIFY call. 2230490a54aSChuck Lever * 2240490a54aSChuck Lever * Linux provides the raw IP address of the monitored host, 2250490a54aSChuck Lever * left in network byte order. 2260490a54aSChuck Lever */ 2270490a54aSChuck Lever static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) 2280490a54aSChuck Lever { 2290490a54aSChuck Lever *p++ = argp->addr; 2300490a54aSChuck Lever *p++ = 0; 2310490a54aSChuck Lever *p++ = 0; 2320490a54aSChuck Lever *p++ = 0; 2330490a54aSChuck Lever 2340490a54aSChuck Lever return p; 2350490a54aSChuck Lever } 2360490a54aSChuck Lever 2371da177e4SLinus Torvalds static int 23852921e02SAl Viro xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 2391da177e4SLinus Torvalds { 2402ca7754dSChuck Lever p = xdr_encode_mon_id(p, argp); 2411da177e4SLinus Torvalds if (IS_ERR(p)) 2421da177e4SLinus Torvalds return PTR_ERR(p); 2439502c522SOlaf Kirch 2440490a54aSChuck Lever p = xdr_encode_priv(p, argp); 2450490a54aSChuck Lever if (IS_ERR(p)) 2460490a54aSChuck Lever return PTR_ERR(p); 2470490a54aSChuck Lever 2481da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 2491da177e4SLinus Torvalds return 0; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds static int 25352921e02SAl Viro xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 2541da177e4SLinus Torvalds { 2552ca7754dSChuck Lever p = xdr_encode_mon_id(p, argp); 2561da177e4SLinus Torvalds if (IS_ERR(p)) 2571da177e4SLinus Torvalds return PTR_ERR(p); 2581da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 2591da177e4SLinus Torvalds return 0; 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds static int 26352921e02SAl Viro xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds resp->status = ntohl(*p++); 2661da177e4SLinus Torvalds resp->state = ntohl(*p++); 2671da177e4SLinus Torvalds dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 2681da177e4SLinus Torvalds resp->status, resp->state); 2691da177e4SLinus Torvalds return 0; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds static int 27352921e02SAl Viro xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 2741da177e4SLinus Torvalds { 2751da177e4SLinus Torvalds resp->state = ntohl(*p++); 2761da177e4SLinus Torvalds return 0; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2802ca7754dSChuck Lever #define SM_my_id_sz (SM_my_name_sz+3) 2812ca7754dSChuck Lever #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2822ca7754dSChuck Lever #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) 2830490a54aSChuck Lever #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) 2840490a54aSChuck Lever #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) 2851da177e4SLinus Torvalds #define SM_monres_sz 2 2861da177e4SLinus Torvalds #define SM_unmonres_sz 1 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds static struct rpc_procinfo nsm_procedures[] = { 2891da177e4SLinus Torvalds [SM_MON] = { 2901da177e4SLinus Torvalds .p_proc = SM_MON, 2911da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_mon, 2921da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat_res, 2932bea90d4SChuck Lever .p_arglen = SM_mon_sz, 2942bea90d4SChuck Lever .p_replen = SM_monres_sz, 295cc0175c1SChuck Lever .p_statidx = SM_MON, 296cc0175c1SChuck Lever .p_name = "MONITOR", 2971da177e4SLinus Torvalds }, 2981da177e4SLinus Torvalds [SM_UNMON] = { 2991da177e4SLinus Torvalds .p_proc = SM_UNMON, 3001da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_unmon, 3011da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat, 3022bea90d4SChuck Lever .p_arglen = SM_mon_id_sz, 3032bea90d4SChuck Lever .p_replen = SM_unmonres_sz, 304cc0175c1SChuck Lever .p_statidx = SM_UNMON, 305cc0175c1SChuck Lever .p_name = "UNMONITOR", 3061da177e4SLinus Torvalds }, 3071da177e4SLinus Torvalds }; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds static struct rpc_version nsm_version1 = { 3101da177e4SLinus Torvalds .number = 1, 311e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nsm_procedures), 3121da177e4SLinus Torvalds .procs = nsm_procedures 3131da177e4SLinus Torvalds }; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds static struct rpc_version * nsm_version[] = { 3161da177e4SLinus Torvalds [1] = &nsm_version1, 3171da177e4SLinus Torvalds }; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds static struct rpc_stat nsm_stats; 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds static struct rpc_program nsm_program = { 3221da177e4SLinus Torvalds .name = "statd", 3231da177e4SLinus Torvalds .number = SM_PROGRAM, 324e8c96f8cSTobias Klauser .nrvers = ARRAY_SIZE(nsm_version), 3251da177e4SLinus Torvalds .version = nsm_version, 3261da177e4SLinus Torvalds .stats = &nsm_stats 3271da177e4SLinus Torvalds }; 328