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 21*9c1bfd03SChuck Lever struct nsm_args { 22*9c1bfd03SChuck Lever __be32 addr; /* remote address */ 23*9c1bfd03SChuck Lever u32 prog; /* RPC callback info */ 24*9c1bfd03SChuck Lever u32 vers; 25*9c1bfd03SChuck Lever u32 proc; 26*9c1bfd03SChuck Lever 27*9c1bfd03SChuck Lever char *mon_name; 28*9c1bfd03SChuck Lever }; 29*9c1bfd03SChuck Lever 30*9c1bfd03SChuck Lever struct nsm_res { 31*9c1bfd03SChuck Lever u32 status; 32*9c1bfd03SChuck Lever u32 state; 33*9c1bfd03SChuck Lever }; 34*9c1bfd03SChuck Lever 351da177e4SLinus Torvalds static struct rpc_clnt * nsm_create(void); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static struct rpc_program nsm_program; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* 401da177e4SLinus Torvalds * Local NSM state 411da177e4SLinus Torvalds */ 42460f5cacSOlaf Kirch int nsm_local_state; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* 451da177e4SLinus Torvalds * Common procedure for SM_MON/SM_UNMON calls 461da177e4SLinus Torvalds */ 471da177e4SLinus Torvalds static int 489502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 491da177e4SLinus Torvalds { 501da177e4SLinus Torvalds struct rpc_clnt *clnt; 511da177e4SLinus Torvalds int status; 52a4846750SChuck Lever struct nsm_args args = { 53a4846750SChuck Lever .addr = nsm_addr_in(nsm)->sin_addr.s_addr, 54a4846750SChuck Lever .prog = NLM_PROGRAM, 55a4846750SChuck Lever .vers = 3, 56a4846750SChuck Lever .proc = NLMPROC_NSM_NOTIFY, 5729ed1407SChuck Lever .mon_name = nsm->sm_mon_name, 58a4846750SChuck Lever }; 59dead28daSChuck Lever struct rpc_message msg = { 60dead28daSChuck Lever .rpc_argp = &args, 61dead28daSChuck Lever .rpc_resp = res, 62dead28daSChuck Lever }; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds clnt = nsm_create(); 651da177e4SLinus Torvalds if (IS_ERR(clnt)) { 661da177e4SLinus Torvalds status = PTR_ERR(clnt); 675acf4315SChuck Lever dprintk("lockd: failed to create NSM upcall transport, " 685acf4315SChuck Lever "status=%d\n", status); 691da177e4SLinus Torvalds goto out; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds memset(res, 0, sizeof(*res)); 731da177e4SLinus Torvalds 74dead28daSChuck Lever msg.rpc_proc = &clnt->cl_procinfo[proc]; 75dead28daSChuck Lever status = rpc_call_sync(clnt, &msg, 0); 761da177e4SLinus Torvalds if (status < 0) 775acf4315SChuck Lever dprintk("lockd: NSM upcall RPC failed, status=%d\n", 781da177e4SLinus Torvalds status); 791da177e4SLinus Torvalds else 801da177e4SLinus Torvalds status = 0; 8190c5755fSTrond Myklebust rpc_shutdown_client(clnt); 821da177e4SLinus Torvalds out: 831da177e4SLinus Torvalds return status; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861e49323cSChuck Lever /** 871e49323cSChuck Lever * nsm_monitor - Notify a peer in case we reboot 881e49323cSChuck Lever * @host: pointer to nlm_host of peer to notify 891e49323cSChuck Lever * 901e49323cSChuck Lever * If this peer is not already monitored, this function sends an 911e49323cSChuck Lever * upcall to the local rpc.statd to record the name/address of 921e49323cSChuck Lever * the peer to notify in case we reboot. 931e49323cSChuck Lever * 941e49323cSChuck Lever * Returns zero if the peer is monitored by the local rpc.statd; 951e49323cSChuck Lever * otherwise a negative errno value is returned. 961da177e4SLinus Torvalds */ 971e49323cSChuck Lever int nsm_monitor(const struct nlm_host *host) 981da177e4SLinus Torvalds { 998dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 1001da177e4SLinus Torvalds struct nsm_res res; 1011da177e4SLinus Torvalds int status; 1021da177e4SLinus Torvalds 1039fee4902SChuck Lever dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); 1048dead0dbSOlaf Kirch 1058dead0dbSOlaf Kirch if (nsm->sm_monitored) 106977faf39SOlaf Kirch return 0; 1071da177e4SLinus Torvalds 10829ed1407SChuck Lever /* 10929ed1407SChuck Lever * Choose whether to record the caller_name or IP address of 11029ed1407SChuck Lever * this peer in the local rpc.statd's database. 11129ed1407SChuck Lever */ 11229ed1407SChuck Lever nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; 11329ed1407SChuck Lever 1149502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_MON, &res); 1155d254b11SChuck Lever if (res.status != 0) 1165d254b11SChuck Lever status = -EIO; 1175d254b11SChuck Lever if (status < 0) 1189fee4902SChuck Lever printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); 1191da177e4SLinus Torvalds else 1208dead0dbSOlaf Kirch nsm->sm_monitored = 1; 1211da177e4SLinus Torvalds return status; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 124356c3eb4SChuck Lever /** 125356c3eb4SChuck Lever * nsm_unmonitor - Unregister peer notification 126356c3eb4SChuck Lever * @host: pointer to nlm_host of peer to stop monitoring 127356c3eb4SChuck Lever * 128356c3eb4SChuck Lever * If this peer is monitored, this function sends an upcall to 129356c3eb4SChuck Lever * tell the local rpc.statd not to send this peer a notification 130356c3eb4SChuck Lever * when we reboot. 1311da177e4SLinus Torvalds */ 132356c3eb4SChuck Lever void nsm_unmonitor(const struct nlm_host *host) 1331da177e4SLinus Torvalds { 1348dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 1351da177e4SLinus Torvalds struct nsm_res res; 136356c3eb4SChuck Lever int status; 1371da177e4SLinus Torvalds 1389502c522SOlaf Kirch if (atomic_read(&nsm->sm_count) == 1 1399502c522SOlaf Kirch && nsm->sm_monitored && !nsm->sm_sticky) { 1409fee4902SChuck Lever dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); 1419502c522SOlaf Kirch 1429502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_UNMON, &res); 1430c7aef45SChuck Lever if (res.status != 0) 1440c7aef45SChuck Lever status = -EIO; 1451da177e4SLinus Torvalds if (status < 0) 1469502c522SOlaf Kirch printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 1479fee4902SChuck Lever nsm->sm_name); 1489502c522SOlaf Kirch else 1498dead0dbSOlaf Kirch nsm->sm_monitored = 0; 150977faf39SOlaf Kirch } 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds /* 1541da177e4SLinus Torvalds * Create NSM client for the local host 1551da177e4SLinus Torvalds */ 1561da177e4SLinus Torvalds static struct rpc_clnt * 1571da177e4SLinus Torvalds nsm_create(void) 1581da177e4SLinus Torvalds { 159e1ec7892SChuck Lever struct sockaddr_in sin = { 160e1ec7892SChuck Lever .sin_family = AF_INET, 161e1ec7892SChuck Lever .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 162e1ec7892SChuck Lever .sin_port = 0, 163e1ec7892SChuck Lever }; 164e1ec7892SChuck Lever struct rpc_create_args args = { 1650896a725S\"Talpey, Thomas\ .protocol = XPRT_TRANSPORT_UDP, 166e1ec7892SChuck Lever .address = (struct sockaddr *)&sin, 167e1ec7892SChuck Lever .addrsize = sizeof(sin), 168e1ec7892SChuck Lever .servername = "localhost", 169e1ec7892SChuck Lever .program = &nsm_program, 170e1ec7892SChuck Lever .version = SM_VERSION, 171e1ec7892SChuck Lever .authflavor = RPC_AUTH_NULL, 172e1ec7892SChuck Lever }; 1731da177e4SLinus Torvalds 174e1ec7892SChuck Lever return rpc_create(&args); 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds /* 1781da177e4SLinus Torvalds * XDR functions for NSM. 1792ca7754dSChuck Lever * 1802ca7754dSChuck Lever * See http://www.opengroup.org/ for details on the Network 1812ca7754dSChuck Lever * Status Monitor wire protocol. 1821da177e4SLinus Torvalds */ 1831da177e4SLinus Torvalds 184099bd05fSChuck Lever static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) 185099bd05fSChuck Lever { 186099bd05fSChuck Lever size_t len = strlen(string); 187099bd05fSChuck Lever 188099bd05fSChuck Lever if (len > SM_MAXSTRLEN) 189099bd05fSChuck Lever len = SM_MAXSTRLEN; 190099bd05fSChuck Lever return xdr_encode_opaque(p, string, len); 191099bd05fSChuck Lever } 192099bd05fSChuck Lever 19349695174SChuck Lever /* 19449695174SChuck Lever * "mon_name" specifies the host to be monitored. 19549695174SChuck Lever */ 19649695174SChuck Lever static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) 19749695174SChuck Lever { 19829ed1407SChuck Lever return xdr_encode_nsm_string(p, argp->mon_name); 19949695174SChuck Lever } 20049695174SChuck Lever 201850c95fdSChuck Lever /* 202850c95fdSChuck Lever * The "my_id" argument specifies the hostname and RPC procedure 203850c95fdSChuck Lever * to be called when the status manager receives notification 204850c95fdSChuck Lever * (via the SM_NOTIFY call) that the state of host "mon_name" 205850c95fdSChuck Lever * has changed. 206850c95fdSChuck Lever */ 207850c95fdSChuck Lever static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) 208850c95fdSChuck Lever { 209850c95fdSChuck Lever p = xdr_encode_nsm_string(p, utsname()->nodename); 210850c95fdSChuck Lever if (!p) 211850c95fdSChuck Lever return ERR_PTR(-EIO); 212850c95fdSChuck Lever 213850c95fdSChuck Lever *p++ = htonl(argp->prog); 214850c95fdSChuck Lever *p++ = htonl(argp->vers); 215850c95fdSChuck Lever *p++ = htonl(argp->proc); 216850c95fdSChuck Lever 217850c95fdSChuck Lever return p; 218850c95fdSChuck Lever } 219850c95fdSChuck Lever 220ea72a7f1SChuck Lever /* 221ea72a7f1SChuck Lever * The "mon_id" argument specifies the non-private arguments 222ea72a7f1SChuck Lever * of an SM_MON or SM_UNMON call. 223ea72a7f1SChuck Lever */ 224ea72a7f1SChuck Lever static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) 225ea72a7f1SChuck Lever { 226ea72a7f1SChuck Lever p = xdr_encode_mon_name(p, argp); 227ea72a7f1SChuck Lever if (!p) 228ea72a7f1SChuck Lever return ERR_PTR(-EIO); 229ea72a7f1SChuck Lever 230ea72a7f1SChuck Lever return xdr_encode_my_id(p, argp); 231ea72a7f1SChuck Lever } 232ea72a7f1SChuck Lever 2330490a54aSChuck Lever /* 2340490a54aSChuck Lever * The "priv" argument may contain private information required 2350490a54aSChuck Lever * by the SM_MON call. This information will be supplied in the 2360490a54aSChuck Lever * SM_NOTIFY call. 2370490a54aSChuck Lever * 2380490a54aSChuck Lever * Linux provides the raw IP address of the monitored host, 2390490a54aSChuck Lever * left in network byte order. 2400490a54aSChuck Lever */ 2410490a54aSChuck Lever static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) 2420490a54aSChuck Lever { 2430490a54aSChuck Lever *p++ = argp->addr; 2440490a54aSChuck Lever *p++ = 0; 2450490a54aSChuck Lever *p++ = 0; 2460490a54aSChuck Lever *p++ = 0; 2470490a54aSChuck Lever 2480490a54aSChuck Lever return p; 2490490a54aSChuck Lever } 2500490a54aSChuck Lever 2511da177e4SLinus Torvalds static int 25252921e02SAl Viro xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 2531da177e4SLinus Torvalds { 2542ca7754dSChuck Lever p = xdr_encode_mon_id(p, argp); 2551da177e4SLinus Torvalds if (IS_ERR(p)) 2561da177e4SLinus Torvalds return PTR_ERR(p); 2579502c522SOlaf Kirch 2580490a54aSChuck Lever p = xdr_encode_priv(p, argp); 2590490a54aSChuck Lever if (IS_ERR(p)) 2600490a54aSChuck Lever return PTR_ERR(p); 2610490a54aSChuck Lever 2621da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 2631da177e4SLinus Torvalds return 0; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds static int 26752921e02SAl Viro xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 2681da177e4SLinus Torvalds { 2692ca7754dSChuck Lever p = xdr_encode_mon_id(p, argp); 2701da177e4SLinus Torvalds if (IS_ERR(p)) 2711da177e4SLinus Torvalds return PTR_ERR(p); 2721da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 2731da177e4SLinus Torvalds return 0; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static int 27752921e02SAl Viro xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 2781da177e4SLinus Torvalds { 2791da177e4SLinus Torvalds resp->status = ntohl(*p++); 2801da177e4SLinus Torvalds resp->state = ntohl(*p++); 2811da177e4SLinus Torvalds dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 2821da177e4SLinus Torvalds resp->status, resp->state); 2831da177e4SLinus Torvalds return 0; 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds static int 28752921e02SAl Viro xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 2881da177e4SLinus Torvalds { 2891da177e4SLinus Torvalds resp->state = ntohl(*p++); 2901da177e4SLinus Torvalds return 0; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2942ca7754dSChuck Lever #define SM_my_id_sz (SM_my_name_sz+3) 2952ca7754dSChuck Lever #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2962ca7754dSChuck Lever #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) 2970490a54aSChuck Lever #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) 2980490a54aSChuck Lever #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) 2991da177e4SLinus Torvalds #define SM_monres_sz 2 3001da177e4SLinus Torvalds #define SM_unmonres_sz 1 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds static struct rpc_procinfo nsm_procedures[] = { 3031da177e4SLinus Torvalds [SM_MON] = { 3041da177e4SLinus Torvalds .p_proc = SM_MON, 3051da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_mon, 3061da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat_res, 3072bea90d4SChuck Lever .p_arglen = SM_mon_sz, 3082bea90d4SChuck Lever .p_replen = SM_monres_sz, 309cc0175c1SChuck Lever .p_statidx = SM_MON, 310cc0175c1SChuck Lever .p_name = "MONITOR", 3111da177e4SLinus Torvalds }, 3121da177e4SLinus Torvalds [SM_UNMON] = { 3131da177e4SLinus Torvalds .p_proc = SM_UNMON, 3141da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_unmon, 3151da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat, 3162bea90d4SChuck Lever .p_arglen = SM_mon_id_sz, 3172bea90d4SChuck Lever .p_replen = SM_unmonres_sz, 318cc0175c1SChuck Lever .p_statidx = SM_UNMON, 319cc0175c1SChuck Lever .p_name = "UNMONITOR", 3201da177e4SLinus Torvalds }, 3211da177e4SLinus Torvalds }; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds static struct rpc_version nsm_version1 = { 3241da177e4SLinus Torvalds .number = 1, 325e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nsm_procedures), 3261da177e4SLinus Torvalds .procs = nsm_procedures 3271da177e4SLinus Torvalds }; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds static struct rpc_version * nsm_version[] = { 3301da177e4SLinus Torvalds [1] = &nsm_version1, 3311da177e4SLinus Torvalds }; 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds static struct rpc_stat nsm_stats; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds static struct rpc_program nsm_program = { 3361da177e4SLinus Torvalds .name = "statd", 3371da177e4SLinus Torvalds .number = SM_PROGRAM, 338e8c96f8cSTobias Klauser .nrvers = ARRAY_SIZE(nsm_version), 3391da177e4SLinus Torvalds .version = nsm_version, 3401da177e4SLinus Torvalds .stats = &nsm_stats 3411da177e4SLinus Torvalds }; 342