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