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