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 2149695174SChuck Lever #define XDR_ADDRBUF_LEN (20) 2249695174SChuck Lever 231da177e4SLinus Torvalds static struct rpc_clnt * nsm_create(void); 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds static struct rpc_program nsm_program; 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 281da177e4SLinus Torvalds * Local NSM state 291da177e4SLinus Torvalds */ 30460f5cacSOlaf Kirch int nsm_local_state; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* 331da177e4SLinus Torvalds * Common procedure for SM_MON/SM_UNMON calls 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds static int 369502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 371da177e4SLinus Torvalds { 381da177e4SLinus Torvalds struct rpc_clnt *clnt; 391da177e4SLinus Torvalds int status; 40a4846750SChuck Lever struct nsm_args args = { 41a4846750SChuck Lever .addr = nsm_addr_in(nsm)->sin_addr.s_addr, 42a4846750SChuck Lever .prog = NLM_PROGRAM, 43a4846750SChuck Lever .vers = 3, 44a4846750SChuck Lever .proc = NLMPROC_NSM_NOTIFY, 45a4846750SChuck Lever .mon_name = nsm->sm_name, 46a4846750SChuck Lever }; 47dead28daSChuck Lever struct rpc_message msg = { 48dead28daSChuck Lever .rpc_argp = &args, 49dead28daSChuck Lever .rpc_resp = res, 50dead28daSChuck Lever }; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds clnt = nsm_create(); 531da177e4SLinus Torvalds if (IS_ERR(clnt)) { 541da177e4SLinus Torvalds status = PTR_ERR(clnt); 55*5acf4315SChuck Lever dprintk("lockd: failed to create NSM upcall transport, " 56*5acf4315SChuck Lever "status=%d\n", status); 571da177e4SLinus Torvalds goto out; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds memset(res, 0, sizeof(*res)); 611da177e4SLinus Torvalds 62dead28daSChuck Lever msg.rpc_proc = &clnt->cl_procinfo[proc]; 63dead28daSChuck Lever status = rpc_call_sync(clnt, &msg, 0); 641da177e4SLinus Torvalds if (status < 0) 65*5acf4315SChuck Lever dprintk("lockd: NSM upcall RPC failed, status=%d\n", 661da177e4SLinus Torvalds status); 671da177e4SLinus Torvalds else 681da177e4SLinus Torvalds status = 0; 6990c5755fSTrond Myklebust rpc_shutdown_client(clnt); 701da177e4SLinus Torvalds out: 711da177e4SLinus Torvalds return status; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* 751da177e4SLinus Torvalds * Set up monitoring of a remote host 761da177e4SLinus Torvalds */ 771da177e4SLinus Torvalds int 781da177e4SLinus Torvalds nsm_monitor(struct nlm_host *host) 791da177e4SLinus Torvalds { 808dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 811da177e4SLinus Torvalds struct nsm_res res; 821da177e4SLinus Torvalds int status; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds dprintk("lockd: nsm_monitor(%s)\n", host->h_name); 858dead0dbSOlaf Kirch BUG_ON(nsm == NULL); 868dead0dbSOlaf Kirch 878dead0dbSOlaf Kirch if (nsm->sm_monitored) 88977faf39SOlaf Kirch return 0; 891da177e4SLinus Torvalds 909502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_MON, &res); 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds if (status < 0 || res.status != 0) 931da177e4SLinus Torvalds printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); 941da177e4SLinus Torvalds else 958dead0dbSOlaf Kirch nsm->sm_monitored = 1; 961da177e4SLinus Torvalds return status; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds /* 1001da177e4SLinus Torvalds * Cease to monitor remote host 1011da177e4SLinus Torvalds */ 1021da177e4SLinus Torvalds int 1031da177e4SLinus Torvalds nsm_unmonitor(struct nlm_host *host) 1041da177e4SLinus Torvalds { 1058dead0dbSOlaf Kirch struct nsm_handle *nsm = host->h_nsmhandle; 1061da177e4SLinus Torvalds struct nsm_res res; 107977faf39SOlaf Kirch int status = 0; 1081da177e4SLinus Torvalds 1098dead0dbSOlaf Kirch if (nsm == NULL) 110977faf39SOlaf Kirch return 0; 1118dead0dbSOlaf Kirch host->h_nsmhandle = NULL; 1121da177e4SLinus Torvalds 1139502c522SOlaf Kirch if (atomic_read(&nsm->sm_count) == 1 1149502c522SOlaf Kirch && nsm->sm_monitored && !nsm->sm_sticky) { 1159502c522SOlaf Kirch dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); 1169502c522SOlaf Kirch 1179502c522SOlaf Kirch status = nsm_mon_unmon(nsm, SM_UNMON, &res); 1181da177e4SLinus Torvalds if (status < 0) 1199502c522SOlaf Kirch printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 1209502c522SOlaf Kirch host->h_name); 1219502c522SOlaf Kirch else 1228dead0dbSOlaf Kirch nsm->sm_monitored = 0; 123977faf39SOlaf Kirch } 1248dead0dbSOlaf Kirch nsm_release(nsm); 1251da177e4SLinus Torvalds return status; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds /* 1291da177e4SLinus Torvalds * Create NSM client for the local host 1301da177e4SLinus Torvalds */ 1311da177e4SLinus Torvalds static struct rpc_clnt * 1321da177e4SLinus Torvalds nsm_create(void) 1331da177e4SLinus Torvalds { 134e1ec7892SChuck Lever struct sockaddr_in sin = { 135e1ec7892SChuck Lever .sin_family = AF_INET, 136e1ec7892SChuck Lever .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 137e1ec7892SChuck Lever .sin_port = 0, 138e1ec7892SChuck Lever }; 139e1ec7892SChuck Lever struct rpc_create_args args = { 1400896a725S\"Talpey, Thomas\ .protocol = XPRT_TRANSPORT_UDP, 141e1ec7892SChuck Lever .address = (struct sockaddr *)&sin, 142e1ec7892SChuck Lever .addrsize = sizeof(sin), 143e1ec7892SChuck Lever .servername = "localhost", 144e1ec7892SChuck Lever .program = &nsm_program, 145e1ec7892SChuck Lever .version = SM_VERSION, 146e1ec7892SChuck Lever .authflavor = RPC_AUTH_NULL, 147e1ec7892SChuck Lever }; 1481da177e4SLinus Torvalds 149e1ec7892SChuck Lever return rpc_create(&args); 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds /* 1531da177e4SLinus Torvalds * XDR functions for NSM. 1542ca7754dSChuck Lever * 1552ca7754dSChuck Lever * See http://www.opengroup.org/ for details on the Network 1562ca7754dSChuck Lever * Status Monitor wire protocol. 1571da177e4SLinus Torvalds */ 1581da177e4SLinus Torvalds 159099bd05fSChuck Lever static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) 160099bd05fSChuck Lever { 161099bd05fSChuck Lever size_t len = strlen(string); 162099bd05fSChuck Lever 163099bd05fSChuck Lever if (len > SM_MAXSTRLEN) 164099bd05fSChuck Lever len = SM_MAXSTRLEN; 165099bd05fSChuck Lever return xdr_encode_opaque(p, string, len); 166099bd05fSChuck Lever } 167099bd05fSChuck Lever 16849695174SChuck Lever /* 16949695174SChuck Lever * "mon_name" specifies the host to be monitored. 17049695174SChuck Lever * 17149695174SChuck Lever * Linux uses a text version of the IP address of the remote 17249695174SChuck Lever * host as the host identifier (the "mon_name" argument). 17349695174SChuck Lever * 17449695174SChuck Lever * Linux statd always looks up the canonical hostname first for 17549695174SChuck Lever * whatever remote hostname it receives, so this works alright. 17649695174SChuck Lever */ 17749695174SChuck Lever static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) 17849695174SChuck Lever { 17949695174SChuck Lever char buffer[XDR_ADDRBUF_LEN + 1]; 18049695174SChuck Lever char *name = argp->mon_name; 18149695174SChuck Lever 18249695174SChuck Lever if (!nsm_use_hostnames) { 18349695174SChuck Lever snprintf(buffer, XDR_ADDRBUF_LEN, 184be859405SHarvey Harrison "%pI4", &argp->addr); 18549695174SChuck Lever name = buffer; 18649695174SChuck Lever } 18749695174SChuck Lever 18849695174SChuck Lever return xdr_encode_nsm_string(p, name); 18949695174SChuck Lever } 19049695174SChuck Lever 191850c95fdSChuck Lever /* 192850c95fdSChuck Lever * The "my_id" argument specifies the hostname and RPC procedure 193850c95fdSChuck Lever * to be called when the status manager receives notification 194850c95fdSChuck Lever * (via the SM_NOTIFY call) that the state of host "mon_name" 195850c95fdSChuck Lever * has changed. 196850c95fdSChuck Lever */ 197850c95fdSChuck Lever static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) 198850c95fdSChuck Lever { 199850c95fdSChuck Lever p = xdr_encode_nsm_string(p, utsname()->nodename); 200850c95fdSChuck Lever if (!p) 201850c95fdSChuck Lever return ERR_PTR(-EIO); 202850c95fdSChuck Lever 203850c95fdSChuck Lever *p++ = htonl(argp->prog); 204850c95fdSChuck Lever *p++ = htonl(argp->vers); 205850c95fdSChuck Lever *p++ = htonl(argp->proc); 206850c95fdSChuck Lever 207850c95fdSChuck Lever return p; 208850c95fdSChuck Lever } 209850c95fdSChuck Lever 210ea72a7f1SChuck Lever /* 211ea72a7f1SChuck Lever * The "mon_id" argument specifies the non-private arguments 212ea72a7f1SChuck Lever * of an SM_MON or SM_UNMON call. 213ea72a7f1SChuck Lever */ 214ea72a7f1SChuck Lever static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) 215ea72a7f1SChuck Lever { 216ea72a7f1SChuck Lever p = xdr_encode_mon_name(p, argp); 217ea72a7f1SChuck Lever if (!p) 218ea72a7f1SChuck Lever return ERR_PTR(-EIO); 219ea72a7f1SChuck Lever 220ea72a7f1SChuck Lever return xdr_encode_my_id(p, argp); 221ea72a7f1SChuck Lever } 222ea72a7f1SChuck Lever 2230490a54aSChuck Lever /* 2240490a54aSChuck Lever * The "priv" argument may contain private information required 2250490a54aSChuck Lever * by the SM_MON call. This information will be supplied in the 2260490a54aSChuck Lever * SM_NOTIFY call. 2270490a54aSChuck Lever * 2280490a54aSChuck Lever * Linux provides the raw IP address of the monitored host, 2290490a54aSChuck Lever * left in network byte order. 2300490a54aSChuck Lever */ 2310490a54aSChuck Lever static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) 2320490a54aSChuck Lever { 2330490a54aSChuck Lever *p++ = argp->addr; 2340490a54aSChuck Lever *p++ = 0; 2350490a54aSChuck Lever *p++ = 0; 2360490a54aSChuck Lever *p++ = 0; 2370490a54aSChuck Lever 2380490a54aSChuck Lever return p; 2390490a54aSChuck Lever } 2400490a54aSChuck Lever 2411da177e4SLinus Torvalds static int 24252921e02SAl Viro xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 2431da177e4SLinus Torvalds { 2442ca7754dSChuck Lever p = xdr_encode_mon_id(p, argp); 2451da177e4SLinus Torvalds if (IS_ERR(p)) 2461da177e4SLinus Torvalds return PTR_ERR(p); 2479502c522SOlaf Kirch 2480490a54aSChuck Lever p = xdr_encode_priv(p, argp); 2490490a54aSChuck Lever if (IS_ERR(p)) 2500490a54aSChuck Lever return PTR_ERR(p); 2510490a54aSChuck Lever 2521da177e4SLinus Torvalds rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 2531da177e4SLinus Torvalds return 0; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static int 25752921e02SAl Viro xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 2581da177e4SLinus Torvalds { 2592ca7754dSChuck Lever p = xdr_encode_mon_id(p, argp); 2601da177e4SLinus Torvalds if (IS_ERR(p)) 2611da177e4SLinus Torvalds return PTR_ERR(p); 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_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 2681da177e4SLinus Torvalds { 2691da177e4SLinus Torvalds resp->status = ntohl(*p++); 2701da177e4SLinus Torvalds resp->state = ntohl(*p++); 2711da177e4SLinus Torvalds dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 2721da177e4SLinus Torvalds resp->status, resp->state); 2731da177e4SLinus Torvalds return 0; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static int 27752921e02SAl Viro xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 2781da177e4SLinus Torvalds { 2791da177e4SLinus Torvalds resp->state = ntohl(*p++); 2801da177e4SLinus Torvalds return 0; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2842ca7754dSChuck Lever #define SM_my_id_sz (SM_my_name_sz+3) 2852ca7754dSChuck Lever #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 2862ca7754dSChuck Lever #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) 2870490a54aSChuck Lever #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) 2880490a54aSChuck Lever #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) 2891da177e4SLinus Torvalds #define SM_monres_sz 2 2901da177e4SLinus Torvalds #define SM_unmonres_sz 1 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static struct rpc_procinfo nsm_procedures[] = { 2931da177e4SLinus Torvalds [SM_MON] = { 2941da177e4SLinus Torvalds .p_proc = SM_MON, 2951da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_mon, 2961da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat_res, 2972bea90d4SChuck Lever .p_arglen = SM_mon_sz, 2982bea90d4SChuck Lever .p_replen = SM_monres_sz, 299cc0175c1SChuck Lever .p_statidx = SM_MON, 300cc0175c1SChuck Lever .p_name = "MONITOR", 3011da177e4SLinus Torvalds }, 3021da177e4SLinus Torvalds [SM_UNMON] = { 3031da177e4SLinus Torvalds .p_proc = SM_UNMON, 3041da177e4SLinus Torvalds .p_encode = (kxdrproc_t) xdr_encode_unmon, 3051da177e4SLinus Torvalds .p_decode = (kxdrproc_t) xdr_decode_stat, 3062bea90d4SChuck Lever .p_arglen = SM_mon_id_sz, 3072bea90d4SChuck Lever .p_replen = SM_unmonres_sz, 308cc0175c1SChuck Lever .p_statidx = SM_UNMON, 309cc0175c1SChuck Lever .p_name = "UNMONITOR", 3101da177e4SLinus Torvalds }, 3111da177e4SLinus Torvalds }; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds static struct rpc_version nsm_version1 = { 3141da177e4SLinus Torvalds .number = 1, 315e8c96f8cSTobias Klauser .nrprocs = ARRAY_SIZE(nsm_procedures), 3161da177e4SLinus Torvalds .procs = nsm_procedures 3171da177e4SLinus Torvalds }; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds static struct rpc_version * nsm_version[] = { 3201da177e4SLinus Torvalds [1] = &nsm_version1, 3211da177e4SLinus Torvalds }; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds static struct rpc_stat nsm_stats; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds static struct rpc_program nsm_program = { 3261da177e4SLinus Torvalds .name = "statd", 3271da177e4SLinus Torvalds .number = SM_PROGRAM, 328e8c96f8cSTobias Klauser .nrvers = ARRAY_SIZE(nsm_version), 3291da177e4SLinus Torvalds .version = nsm_version, 3301da177e4SLinus Torvalds .stats = &nsm_stats 3311da177e4SLinus Torvalds }; 332