1 /* 2 * linux/fs/lockd/mon.c 3 * 4 * The kernel statd client. 5 * 6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 7 */ 8 9 #include <linux/types.h> 10 #include <linux/utsname.h> 11 #include <linux/kernel.h> 12 #include <linux/sunrpc/clnt.h> 13 #include <linux/sunrpc/xprtsock.h> 14 #include <linux/sunrpc/svc.h> 15 #include <linux/lockd/lockd.h> 16 #include <linux/lockd/sm_inter.h> 17 18 19 #define NLMDBG_FACILITY NLMDBG_MONITOR 20 21 static struct rpc_clnt * nsm_create(void); 22 23 static struct rpc_program nsm_program; 24 25 /* 26 * Local NSM state 27 */ 28 int nsm_local_state; 29 30 /* 31 * Common procedure for SM_MON/SM_UNMON calls 32 */ 33 static int 34 nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 35 { 36 struct rpc_clnt *clnt; 37 int status; 38 struct nsm_args args = { 39 .addr = nsm_addr_in(nsm)->sin_addr.s_addr, 40 .prog = NLM_PROGRAM, 41 .vers = 3, 42 .proc = NLMPROC_NSM_NOTIFY, 43 .mon_name = nsm->sm_mon_name, 44 }; 45 struct rpc_message msg = { 46 .rpc_argp = &args, 47 .rpc_resp = res, 48 }; 49 50 clnt = nsm_create(); 51 if (IS_ERR(clnt)) { 52 status = PTR_ERR(clnt); 53 dprintk("lockd: failed to create NSM upcall transport, " 54 "status=%d\n", status); 55 goto out; 56 } 57 58 memset(res, 0, sizeof(*res)); 59 60 msg.rpc_proc = &clnt->cl_procinfo[proc]; 61 status = rpc_call_sync(clnt, &msg, 0); 62 if (status < 0) 63 dprintk("lockd: NSM upcall RPC failed, status=%d\n", 64 status); 65 else 66 status = 0; 67 rpc_shutdown_client(clnt); 68 out: 69 return status; 70 } 71 72 /** 73 * nsm_monitor - Notify a peer in case we reboot 74 * @host: pointer to nlm_host of peer to notify 75 * 76 * If this peer is not already monitored, this function sends an 77 * upcall to the local rpc.statd to record the name/address of 78 * the peer to notify in case we reboot. 79 * 80 * Returns zero if the peer is monitored by the local rpc.statd; 81 * otherwise a negative errno value is returned. 82 */ 83 int nsm_monitor(const struct nlm_host *host) 84 { 85 struct nsm_handle *nsm = host->h_nsmhandle; 86 struct nsm_res res; 87 int status; 88 89 dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); 90 91 if (nsm->sm_monitored) 92 return 0; 93 94 /* 95 * Choose whether to record the caller_name or IP address of 96 * this peer in the local rpc.statd's database. 97 */ 98 nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; 99 100 status = nsm_mon_unmon(nsm, SM_MON, &res); 101 if (res.status != 0) 102 status = -EIO; 103 if (status < 0) 104 printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); 105 else 106 nsm->sm_monitored = 1; 107 return status; 108 } 109 110 /* 111 * Cease to monitor remote host 112 */ 113 int 114 nsm_unmonitor(struct nlm_host *host) 115 { 116 struct nsm_handle *nsm = host->h_nsmhandle; 117 struct nsm_res res; 118 int status = 0; 119 120 if (atomic_read(&nsm->sm_count) == 1 121 && nsm->sm_monitored && !nsm->sm_sticky) { 122 dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); 123 124 status = nsm_mon_unmon(nsm, SM_UNMON, &res); 125 if (status < 0) 126 printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 127 nsm->sm_name); 128 else 129 nsm->sm_monitored = 0; 130 } 131 return status; 132 } 133 134 /* 135 * Create NSM client for the local host 136 */ 137 static struct rpc_clnt * 138 nsm_create(void) 139 { 140 struct sockaddr_in sin = { 141 .sin_family = AF_INET, 142 .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 143 .sin_port = 0, 144 }; 145 struct rpc_create_args args = { 146 .protocol = XPRT_TRANSPORT_UDP, 147 .address = (struct sockaddr *)&sin, 148 .addrsize = sizeof(sin), 149 .servername = "localhost", 150 .program = &nsm_program, 151 .version = SM_VERSION, 152 .authflavor = RPC_AUTH_NULL, 153 }; 154 155 return rpc_create(&args); 156 } 157 158 /* 159 * XDR functions for NSM. 160 * 161 * See http://www.opengroup.org/ for details on the Network 162 * Status Monitor wire protocol. 163 */ 164 165 static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) 166 { 167 size_t len = strlen(string); 168 169 if (len > SM_MAXSTRLEN) 170 len = SM_MAXSTRLEN; 171 return xdr_encode_opaque(p, string, len); 172 } 173 174 /* 175 * "mon_name" specifies the host to be monitored. 176 */ 177 static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) 178 { 179 return xdr_encode_nsm_string(p, argp->mon_name); 180 } 181 182 /* 183 * The "my_id" argument specifies the hostname and RPC procedure 184 * to be called when the status manager receives notification 185 * (via the SM_NOTIFY call) that the state of host "mon_name" 186 * has changed. 187 */ 188 static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) 189 { 190 p = xdr_encode_nsm_string(p, utsname()->nodename); 191 if (!p) 192 return ERR_PTR(-EIO); 193 194 *p++ = htonl(argp->prog); 195 *p++ = htonl(argp->vers); 196 *p++ = htonl(argp->proc); 197 198 return p; 199 } 200 201 /* 202 * The "mon_id" argument specifies the non-private arguments 203 * of an SM_MON or SM_UNMON call. 204 */ 205 static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) 206 { 207 p = xdr_encode_mon_name(p, argp); 208 if (!p) 209 return ERR_PTR(-EIO); 210 211 return xdr_encode_my_id(p, argp); 212 } 213 214 /* 215 * The "priv" argument may contain private information required 216 * by the SM_MON call. This information will be supplied in the 217 * SM_NOTIFY call. 218 * 219 * Linux provides the raw IP address of the monitored host, 220 * left in network byte order. 221 */ 222 static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) 223 { 224 *p++ = argp->addr; 225 *p++ = 0; 226 *p++ = 0; 227 *p++ = 0; 228 229 return p; 230 } 231 232 static int 233 xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 234 { 235 p = xdr_encode_mon_id(p, argp); 236 if (IS_ERR(p)) 237 return PTR_ERR(p); 238 239 p = xdr_encode_priv(p, argp); 240 if (IS_ERR(p)) 241 return PTR_ERR(p); 242 243 rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 244 return 0; 245 } 246 247 static int 248 xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 249 { 250 p = xdr_encode_mon_id(p, argp); 251 if (IS_ERR(p)) 252 return PTR_ERR(p); 253 rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 254 return 0; 255 } 256 257 static int 258 xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 259 { 260 resp->status = ntohl(*p++); 261 resp->state = ntohl(*p++); 262 dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 263 resp->status, resp->state); 264 return 0; 265 } 266 267 static int 268 xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 269 { 270 resp->state = ntohl(*p++); 271 return 0; 272 } 273 274 #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 275 #define SM_my_id_sz (SM_my_name_sz+3) 276 #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) 277 #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) 278 #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) 279 #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) 280 #define SM_monres_sz 2 281 #define SM_unmonres_sz 1 282 283 static struct rpc_procinfo nsm_procedures[] = { 284 [SM_MON] = { 285 .p_proc = SM_MON, 286 .p_encode = (kxdrproc_t) xdr_encode_mon, 287 .p_decode = (kxdrproc_t) xdr_decode_stat_res, 288 .p_arglen = SM_mon_sz, 289 .p_replen = SM_monres_sz, 290 .p_statidx = SM_MON, 291 .p_name = "MONITOR", 292 }, 293 [SM_UNMON] = { 294 .p_proc = SM_UNMON, 295 .p_encode = (kxdrproc_t) xdr_encode_unmon, 296 .p_decode = (kxdrproc_t) xdr_decode_stat, 297 .p_arglen = SM_mon_id_sz, 298 .p_replen = SM_unmonres_sz, 299 .p_statidx = SM_UNMON, 300 .p_name = "UNMONITOR", 301 }, 302 }; 303 304 static struct rpc_version nsm_version1 = { 305 .number = 1, 306 .nrprocs = ARRAY_SIZE(nsm_procedures), 307 .procs = nsm_procedures 308 }; 309 310 static struct rpc_version * nsm_version[] = { 311 [1] = &nsm_version1, 312 }; 313 314 static struct rpc_stat nsm_stats; 315 316 static struct rpc_program nsm_program = { 317 .name = "statd", 318 .number = SM_PROGRAM, 319 .nrvers = ARRAY_SIZE(nsm_version), 320 .version = nsm_version, 321 .stats = &nsm_stats 322 }; 323