1 /* 2 * linux/fs/nfs/callback.c 3 * 4 * Copyright (C) 2004 Trond Myklebust 5 * 6 * NFSv4 callback handling 7 */ 8 9 #include <linux/config.h> 10 #include <linux/completion.h> 11 #include <linux/ip.h> 12 #include <linux/module.h> 13 #include <linux/smp_lock.h> 14 #include <linux/sunrpc/svc.h> 15 #include <linux/sunrpc/svcsock.h> 16 #include <linux/nfs_fs.h> 17 #include <linux/mutex.h> 18 19 #include <net/inet_sock.h> 20 21 #include "nfs4_fs.h" 22 #include "callback.h" 23 24 #define NFSDBG_FACILITY NFSDBG_CALLBACK 25 26 struct nfs_callback_data { 27 unsigned int users; 28 struct svc_serv *serv; 29 pid_t pid; 30 struct completion started; 31 struct completion stopped; 32 }; 33 34 static struct nfs_callback_data nfs_callback_info; 35 static DEFINE_MUTEX(nfs_callback_mutex); 36 static struct svc_program nfs4_callback_program; 37 38 unsigned int nfs_callback_set_tcpport; 39 unsigned short nfs_callback_tcpport; 40 41 /* 42 * This is the callback kernel thread. 43 */ 44 static void nfs_callback_svc(struct svc_rqst *rqstp) 45 { 46 struct svc_serv *serv = rqstp->rq_server; 47 int err; 48 49 __module_get(THIS_MODULE); 50 lock_kernel(); 51 52 nfs_callback_info.pid = current->pid; 53 daemonize("nfsv4-svc"); 54 /* Process request with signals blocked, but allow SIGKILL. */ 55 allow_signal(SIGKILL); 56 57 complete(&nfs_callback_info.started); 58 59 for(;;) { 60 if (signalled()) { 61 if (nfs_callback_info.users == 0) 62 break; 63 flush_signals(current); 64 } 65 /* 66 * Listen for a request on the socket 67 */ 68 err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT); 69 if (err == -EAGAIN || err == -EINTR) 70 continue; 71 if (err < 0) { 72 printk(KERN_WARNING 73 "%s: terminating on error %d\n", 74 __FUNCTION__, -err); 75 break; 76 } 77 dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__, 78 NIPQUAD(rqstp->rq_addr.sin_addr.s_addr)); 79 svc_process(serv, rqstp); 80 } 81 82 svc_exit_thread(rqstp); 83 nfs_callback_info.pid = 0; 84 complete(&nfs_callback_info.stopped); 85 unlock_kernel(); 86 module_put_and_exit(0); 87 } 88 89 /* 90 * Bring up the server process if it is not already up. 91 */ 92 int nfs_callback_up(void) 93 { 94 struct svc_serv *serv; 95 struct svc_sock *svsk; 96 int ret = 0; 97 98 lock_kernel(); 99 mutex_lock(&nfs_callback_mutex); 100 if (nfs_callback_info.users++ || nfs_callback_info.pid != 0) 101 goto out; 102 init_completion(&nfs_callback_info.started); 103 init_completion(&nfs_callback_info.stopped); 104 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE); 105 ret = -ENOMEM; 106 if (!serv) 107 goto out_err; 108 /* FIXME: We don't want to register this socket with the portmapper */ 109 ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport); 110 if (ret < 0) 111 goto out_destroy; 112 if (!list_empty(&serv->sv_permsocks)) { 113 svsk = list_entry(serv->sv_permsocks.next, 114 struct svc_sock, sk_list); 115 nfs_callback_tcpport = ntohs(inet_sk(svsk->sk_sk)->sport); 116 dprintk ("Callback port = 0x%x\n", nfs_callback_tcpport); 117 } else 118 BUG(); 119 ret = svc_create_thread(nfs_callback_svc, serv); 120 if (ret < 0) 121 goto out_destroy; 122 nfs_callback_info.serv = serv; 123 wait_for_completion(&nfs_callback_info.started); 124 out: 125 mutex_unlock(&nfs_callback_mutex); 126 unlock_kernel(); 127 return ret; 128 out_destroy: 129 svc_destroy(serv); 130 out_err: 131 nfs_callback_info.users--; 132 goto out; 133 } 134 135 /* 136 * Kill the server process if it is not already up. 137 */ 138 int nfs_callback_down(void) 139 { 140 int ret = 0; 141 142 lock_kernel(); 143 mutex_lock(&nfs_callback_mutex); 144 nfs_callback_info.users--; 145 do { 146 if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0) 147 break; 148 if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0) 149 break; 150 } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); 151 mutex_unlock(&nfs_callback_mutex); 152 unlock_kernel(); 153 return ret; 154 } 155 156 static int nfs_callback_authenticate(struct svc_rqst *rqstp) 157 { 158 struct in_addr *addr = &rqstp->rq_addr.sin_addr; 159 struct nfs4_client *clp; 160 161 /* Don't talk to strangers */ 162 clp = nfs4_find_client(addr); 163 if (clp == NULL) 164 return SVC_DROP; 165 dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr)); 166 nfs4_put_client(clp); 167 switch (rqstp->rq_authop->flavour) { 168 case RPC_AUTH_NULL: 169 if (rqstp->rq_proc != CB_NULL) 170 return SVC_DENIED; 171 break; 172 case RPC_AUTH_UNIX: 173 break; 174 case RPC_AUTH_GSS: 175 /* FIXME: RPCSEC_GSS handling? */ 176 default: 177 return SVC_DENIED; 178 } 179 return SVC_OK; 180 } 181 182 /* 183 * Define NFS4 callback program 184 */ 185 extern struct svc_version nfs4_callback_version1; 186 187 static struct svc_version *nfs4_callback_version[] = { 188 [1] = &nfs4_callback_version1, 189 }; 190 191 static struct svc_stat nfs4_callback_stats; 192 193 static struct svc_program nfs4_callback_program = { 194 .pg_prog = NFS4_CALLBACK, /* RPC service number */ 195 .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */ 196 .pg_vers = nfs4_callback_version, /* version table */ 197 .pg_name = "NFSv4 callback", /* service name */ 198 .pg_class = "nfs", /* authentication class */ 199 .pg_stats = &nfs4_callback_stats, 200 .pg_authenticate = nfs_callback_authenticate, 201 }; 202