~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/afs/cmservice.c

Version: ~ [ linux-5.0-rc6 ] ~ [ linux-4.20.10 ] ~ [ linux-4.19.23 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.101 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.158 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.174 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.134 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* cmservice.c: AFS Cache Manager Service
  2  *
  3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  4  * Written by David Howells (dhowells@redhat.com)
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public License
  8  * as published by the Free Software Foundation; either version
  9  * 2 of the License, or (at your option) any later version.
 10  */
 11 
 12 #include <linux/module.h>
 13 #include <linux/init.h>
 14 #include <linux/sched.h>
 15 #include <linux/completion.h>
 16 #include "server.h"
 17 #include "cell.h"
 18 #include "transport.h"
 19 #include <rxrpc/rxrpc.h>
 20 #include <rxrpc/transport.h>
 21 #include <rxrpc/connection.h>
 22 #include <rxrpc/call.h>
 23 #include "cmservice.h"
 24 #include "internal.h"
 25 
 26 static unsigned afscm_usage;            /* AFS cache manager usage count */
 27 static struct rw_semaphore afscm_sem;   /* AFS cache manager start/stop semaphore */
 28 
 29 static int afscm_new_call(struct rxrpc_call *call);
 30 static void afscm_attention(struct rxrpc_call *call);
 31 static void afscm_error(struct rxrpc_call *call);
 32 static void afscm_aemap(struct rxrpc_call *call);
 33 
 34 static void _SRXAFSCM_CallBack(struct rxrpc_call *call);
 35 static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call);
 36 static void _SRXAFSCM_Probe(struct rxrpc_call *call);
 37 
 38 typedef void (*_SRXAFSCM_xxxx_t)(struct rxrpc_call *call);
 39 
 40 static const struct rxrpc_operation AFSCM_ops[] = {
 41         {
 42                 .id     = 204,
 43                 .asize  = RXRPC_APP_MARK_EOF,
 44                 .name   = "CallBack",
 45                 .user   = _SRXAFSCM_CallBack,
 46         },
 47         {
 48                 .id     = 205,
 49                 .asize  = RXRPC_APP_MARK_EOF,
 50                 .name   = "InitCallBackState",
 51                 .user   = _SRXAFSCM_InitCallBackState,
 52         },
 53         {
 54                 .id     = 206,
 55                 .asize  = RXRPC_APP_MARK_EOF,
 56                 .name   = "Probe",
 57                 .user   = _SRXAFSCM_Probe,
 58         },
 59 #if 0
 60         {
 61                 .id     = 207,
 62                 .asize  = RXRPC_APP_MARK_EOF,
 63                 .name   = "GetLock",
 64                 .user   = _SRXAFSCM_GetLock,
 65         },
 66         {
 67                 .id     = 208,
 68                 .asize  = RXRPC_APP_MARK_EOF,
 69                 .name   = "GetCE",
 70                 .user   = _SRXAFSCM_GetCE,
 71         },
 72         {
 73                 .id     = 209,
 74                 .asize  = RXRPC_APP_MARK_EOF,
 75                 .name   = "GetXStatsVersion",
 76                 .user   = _SRXAFSCM_GetXStatsVersion,
 77         },
 78         {
 79                 .id     = 210,
 80                 .asize  = RXRPC_APP_MARK_EOF,
 81                 .name   = "GetXStats",
 82                 .user   = _SRXAFSCM_GetXStats,
 83         }
 84 #endif
 85 };
 86 
 87 static struct rxrpc_service AFSCM_service = {
 88         .name           = "AFS/CM",
 89         .owner          = THIS_MODULE,
 90         .link           = LIST_HEAD_INIT(AFSCM_service.link),
 91         .new_call       = afscm_new_call,
 92         .service_id     = 1,
 93         .attn_func      = afscm_attention,
 94         .error_func     = afscm_error,
 95         .aemap_func     = afscm_aemap,
 96         .ops_begin      = &AFSCM_ops[0],
 97         .ops_end        = &AFSCM_ops[sizeof(AFSCM_ops)/sizeof(AFSCM_ops[0])],
 98 };
 99 
100 static DECLARE_COMPLETION(kafscmd_alive);
101 static DECLARE_COMPLETION(kafscmd_dead);
102 static DECLARE_WAIT_QUEUE_HEAD(kafscmd_sleepq);
103 static LIST_HEAD(kafscmd_attention_list);
104 static LIST_HEAD(afscm_calls);
105 static spinlock_t afscm_calls_lock = SPIN_LOCK_UNLOCKED;
106 static spinlock_t kafscmd_attention_lock = SPIN_LOCK_UNLOCKED;
107 static int kafscmd_die;
108 
109 /*****************************************************************************/
110 /*
111  * AFS Cache Manager kernel thread
112  */
113 static int kafscmd(void *arg)
114 {
115         DECLARE_WAITQUEUE(myself,current);
116 
117         struct rxrpc_call *call;
118         _SRXAFSCM_xxxx_t func;
119         int die;
120 
121         printk("kAFS: Started kafscmd %d\n",current->pid);
122 
123         daemonize("kafscmd");
124 
125         complete(&kafscmd_alive);
126 
127         /* loop around looking for things to attend to */
128         do {
129                 if (list_empty(&kafscmd_attention_list)) {
130                         set_current_state(TASK_INTERRUPTIBLE);
131                         add_wait_queue(&kafscmd_sleepq,&myself);
132 
133                         for (;;) {
134                                 set_current_state(TASK_INTERRUPTIBLE);
135                                 if (!list_empty(&kafscmd_attention_list) ||
136                                     signal_pending(current) ||
137                                     kafscmd_die)
138                                         break;
139 
140                                 schedule();
141                         }
142 
143                         remove_wait_queue(&kafscmd_sleepq,&myself);
144                         set_current_state(TASK_RUNNING);
145                 }
146 
147                 die = kafscmd_die;
148 
149                 /* dequeue the next call requiring attention */
150                 call = NULL;
151                 spin_lock(&kafscmd_attention_lock);
152 
153                 if (!list_empty(&kafscmd_attention_list)) {
154                         call = list_entry(kafscmd_attention_list.next,
155                                           struct rxrpc_call,
156                                           app_attn_link);
157                         list_del_init(&call->app_attn_link);
158                         die = 0;
159                 }
160 
161                 spin_unlock(&kafscmd_attention_lock);
162 
163                 if (call) {
164                         /* act upon it */
165                         _debug("@@@ Begin Attend Call %p",call);
166 
167                         func = call->app_user;
168                         if (func)
169                                 func(call);
170 
171                         rxrpc_put_call(call);
172 
173                         _debug("@@@ End Attend Call %p",call);
174                 }
175 
176         } while(!die);
177 
178         /* and that's all */
179         complete_and_exit(&kafscmd_dead,0);
180 
181 } /* end kafscmd() */
182 
183 /*****************************************************************************/
184 /*
185  * handle a call coming in to the cache manager
186  * - if I want to keep the call, I must increment its usage count
187  * - the return value will be negated and passed back in an abort packet if non-zero
188  * - serialised by virtue of there only being one krxiod
189  */
190 static int afscm_new_call(struct rxrpc_call *call)
191 {
192         _enter("%p{cid=%u u=%d}",call,ntohl(call->call_id),atomic_read(&call->usage));
193 
194         rxrpc_get_call(call);
195 
196         /* add to my current call list */
197         spin_lock(&afscm_calls_lock);
198         list_add(&call->app_link,&afscm_calls);
199         spin_unlock(&afscm_calls_lock);
200 
201         _leave(" = 0");
202         return 0;
203 
204 } /* end afscm_new_call() */
205 
206 /*****************************************************************************/
207 /*
208  * queue on the kafscmd queue for attention
209  */
210 static void afscm_attention(struct rxrpc_call *call)
211 {
212         _enter("%p{cid=%u u=%d}",call,ntohl(call->call_id),atomic_read(&call->usage));
213 
214         spin_lock(&kafscmd_attention_lock);
215 
216         if (list_empty(&call->app_attn_link)) {
217                 list_add_tail(&call->app_attn_link,&kafscmd_attention_list);
218                 rxrpc_get_call(call);
219         }
220 
221         spin_unlock(&kafscmd_attention_lock);
222 
223         wake_up(&kafscmd_sleepq);
224 
225         _leave(" {u=%d}",atomic_read(&call->usage));
226 } /* end afscm_attention() */
227 
228 /*****************************************************************************/
229 /*
230  * handle my call being aborted
231  * - clean up, dequeue and put my ref to the call
232  */
233 static void afscm_error(struct rxrpc_call *call)
234 {
235         int removed;
236 
237         _enter("%p{est=%s ac=%u er=%d}",
238                call,
239                rxrpc_call_error_states[call->app_err_state],
240                call->app_abort_code,
241                call->app_errno);
242 
243         spin_lock(&kafscmd_attention_lock);
244 
245         if (list_empty(&call->app_attn_link)) {
246                 list_add_tail(&call->app_attn_link,&kafscmd_attention_list);
247                 rxrpc_get_call(call);
248         }
249 
250         spin_unlock(&kafscmd_attention_lock);
251 
252         removed = 0;
253         spin_lock(&afscm_calls_lock);
254         if (!list_empty(&call->app_link)) {
255                 list_del_init(&call->app_link);
256                 removed = 1;
257         }
258         spin_unlock(&afscm_calls_lock);
259 
260         if (removed)
261                 rxrpc_put_call(call);
262 
263         wake_up(&kafscmd_sleepq);
264 
265         _leave("");
266 } /* end afscm_error() */
267 
268 /*****************************************************************************/
269 /*
270  * map afs abort codes to/from Linux error codes
271  * - called with call->lock held
272  */
273 static void afscm_aemap(struct rxrpc_call *call)
274 {
275         switch (call->app_err_state) {
276         case RXRPC_ESTATE_LOCAL_ABORT:
277                 call->app_abort_code = -call->app_errno;
278                 break;
279         case RXRPC_ESTATE_PEER_ABORT:
280                 call->app_errno = -ECONNABORTED;
281                 break;
282         default:
283                 break;
284         }
285 } /* end afscm_aemap() */
286 
287 /*****************************************************************************/
288 /*
289  * start the cache manager service if not already started
290  */
291 int afscm_start(void)
292 {
293         int ret;
294 
295         down_write(&afscm_sem);
296         if (!afscm_usage) {
297                 ret = kernel_thread(kafscmd, NULL, 0);
298                 if (ret < 0)
299                         goto out;
300 
301                 wait_for_completion(&kafscmd_alive);
302 
303                 ret = rxrpc_add_service(afs_transport, &AFSCM_service);
304                 if (ret<0)
305                         goto kill;
306 
307 #ifdef AFS_AUTOMOUNT_SUPPORT
308                 afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
309                                         afs_mntpt_expiry_timeout * HZ);
310 #endif
311         }
312 
313         afscm_usage++;
314         up_write(&afscm_sem);
315 
316         return 0;
317 
318  kill:
319         kafscmd_die = 1;
320         wake_up(&kafscmd_sleepq);
321         wait_for_completion(&kafscmd_dead);
322 
323  out:
324         up_write(&afscm_sem);
325         return ret;
326 
327 } /* end afscm_start() */
328 
329 /*****************************************************************************/
330 /*
331  * stop the cache manager service
332  */
333 void afscm_stop(void)
334 {
335         struct rxrpc_call *call;
336 
337         down_write(&afscm_sem);
338 
339         if (afscm_usage == 0) BUG();
340         afscm_usage--;
341 
342         if (afscm_usage == 0) {
343                 /* don't want more incoming calls */
344                 rxrpc_del_service(afs_transport, &AFSCM_service);
345 
346                 /* abort any calls I've still got open (the afscm_error() will dequeue them) */
347                 spin_lock(&afscm_calls_lock);
348                 while (!list_empty(&afscm_calls)) {
349                         call = list_entry(afscm_calls.next,
350                                           struct rxrpc_call,
351                                           app_link);
352 
353                         list_del_init(&call->app_link);
354                         rxrpc_get_call(call);
355                         spin_unlock(&afscm_calls_lock);
356 
357                         rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */
358 
359                         _debug("nuking active call %08x.%d",
360                                ntohl(call->conn->conn_id),
361                                ntohl(call->call_id));
362                         rxrpc_put_call(call);
363                         rxrpc_put_call(call);
364 
365                         spin_lock(&afscm_calls_lock);
366                 }
367                 spin_unlock(&afscm_calls_lock);
368 
369                 /* get rid of my daemon */
370                 kafscmd_die = 1;
371                 wake_up(&kafscmd_sleepq);
372                 wait_for_completion(&kafscmd_dead);
373 
374                 /* dispose of any calls waiting for attention */
375                 spin_lock(&kafscmd_attention_lock);
376                 while (!list_empty(&kafscmd_attention_list)) {
377                         call = list_entry(kafscmd_attention_list.next,
378                                           struct rxrpc_call,
379                                           app_attn_link);
380 
381                         list_del_init(&call->app_attn_link);
382                         spin_unlock(&kafscmd_attention_lock);
383 
384                         rxrpc_put_call(call);
385 
386                         spin_lock(&kafscmd_attention_lock);
387                 }
388                 spin_unlock(&kafscmd_attention_lock);
389 
390 #ifdef AFS_AUTOMOUNT_SUPPORT
391                 afs_kafstimod_del_timer(&afs_mntpt_expiry_timer);
392 #endif
393         }
394 
395         up_write(&afscm_sem);
396 
397 } /* end afscm_stop() */
398 
399 /*****************************************************************************/
400 /*
401  * handle the fileserver breaking a set of callbacks
402  */
403 static void _SRXAFSCM_CallBack(struct rxrpc_call *call)
404 {
405         afs_server_t *server;
406         size_t count, qty, tmp;
407         int ret = 0, removed;
408 
409         _enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
410 
411         server = afs_server_get_from_peer(call->conn->peer);
412 
413         switch (call->app_call_state) {
414                 /* we've received the last packet
415                  * - drain all the data from the call and send the reply
416                  */
417         case RXRPC_CSTATE_SRVR_GOT_ARGS:
418                 ret = -EBADMSG;
419                 qty = call->app_ready_qty;
420                 if (qty<8 || qty>50*(6*4)+8)
421                         break;
422 
423                 {
424                         afs_callback_t *cb, *pcb;
425                         int loop;
426                         u32 *fp, *bp;
427 
428                         fp = rxrpc_call_alloc_scratch(call,qty);
429 
430                         /* drag the entire argument block out to the scratch space */
431                         ret = rxrpc_call_read_data(call,fp,qty,0);
432                         if (ret<0)
433                                 break;
434 
435                         /* and unmarshall the parameter block */
436                         ret = -EBADMSG;
437                         count = ntohl(*fp++);
438                         if (count>AFSCBMAX ||
439                             (count*(3*4)+8 != qty && count*(6*4)+8 != qty))
440                                 break;
441 
442                         bp = fp + count*3;
443                         tmp = ntohl(*bp++);
444                         if (tmp>0 && tmp!=count)
445                                 break;
446                         if (tmp==0)
447                                 bp = NULL;
448 
449                         pcb = cb = rxrpc_call_alloc_scratch_s(call,afs_callback_t);
450 
451                         for (loop=count-1; loop>=0; loop--) {
452                                 pcb->fid.vid    = ntohl(*fp++);
453                                 pcb->fid.vnode  = ntohl(*fp++);
454                                 pcb->fid.unique = ntohl(*fp++);
455                                 if (bp) {
456                                         pcb->version    = ntohl(*bp++);
457                                         pcb->expiry     = ntohl(*bp++);
458                                         pcb->type       = ntohl(*bp++);
459                                 }
460                                 else {
461                                         pcb->version    = 0;
462                                         pcb->expiry     = 0;
463                                         pcb->type       = AFSCM_CB_UNTYPED;
464                                 }
465                                 pcb++;
466                         }
467 
468                         /* invoke the actual service routine */
469                         ret = SRXAFSCM_CallBack(server,count,cb);
470                         if (ret<0)
471                                 break;
472                 }
473 
474                 /* send the reply */
475                 ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
476                 if (ret<0)
477                         break;
478                 break;
479 
480                 /* operation complete */
481         case RXRPC_CSTATE_COMPLETE:
482                 call->app_user = NULL;
483                 removed = 0;
484                 spin_lock(&afscm_calls_lock);
485                 if (!list_empty(&call->app_link)) {
486                         list_del_init(&call->app_link);
487                         removed = 1;
488                 }
489                 spin_unlock(&afscm_calls_lock);
490 
491                 if (removed)
492                         rxrpc_put_call(call);
493                 break;
494 
495                 /* operation terminated on error */
496         case RXRPC_CSTATE_ERROR:
497                 call->app_user = NULL;
498                 break;
499 
500         default:
501                 break;
502         }
503 
504         if (ret<0)
505                 rxrpc_call_abort(call,ret);
506 
507         afs_put_server(server);
508 
509         _leave(" = %d",ret);
510 
511 } /* end _SRXAFSCM_CallBack() */
512 
513 /*****************************************************************************/
514 /*
515  * handle the fileserver asking us to initialise our callback state
516  */
517 static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call)
518 {
519         afs_server_t *server;
520         size_t count;
521         int ret = 0, removed;
522 
523         _enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
524 
525         server = afs_server_get_from_peer(call->conn->peer);
526 
527         switch (call->app_call_state) {
528                 /* we've received the last packet - drain all the data from the call */
529         case RXRPC_CSTATE_SRVR_GOT_ARGS:
530                 /* shouldn't be any args */
531                 ret = -EBADMSG;
532                 break;
533 
534                 /* send the reply when asked for it */
535         case RXRPC_CSTATE_SRVR_SND_REPLY:
536                 /* invoke the actual service routine */
537                 ret = SRXAFSCM_InitCallBackState(server);
538                 if (ret<0)
539                         break;
540 
541                 ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
542                 if (ret<0)
543                         break;
544                 break;
545 
546                 /* operation complete */
547         case RXRPC_CSTATE_COMPLETE:
548                 call->app_user = NULL;
549                 removed = 0;
550                 spin_lock(&afscm_calls_lock);
551                 if (!list_empty(&call->app_link)) {
552                         list_del_init(&call->app_link);
553                         removed = 1;
554                 }
555                 spin_unlock(&afscm_calls_lock);
556 
557                 if (removed)
558                         rxrpc_put_call(call);
559                 break;
560 
561                 /* operation terminated on error */
562         case RXRPC_CSTATE_ERROR:
563                 call->app_user = NULL;
564                 break;
565 
566         default:
567                 break;
568         }
569 
570         if (ret<0)
571                 rxrpc_call_abort(call,ret);
572 
573         afs_put_server(server);
574 
575         _leave(" = %d",ret);
576 
577 } /* end _SRXAFSCM_InitCallBackState() */
578 
579 /*****************************************************************************/
580 /*
581  * handle a probe from a fileserver
582  */
583 static void _SRXAFSCM_Probe(struct rxrpc_call *call)
584 {
585         afs_server_t *server;
586         size_t count;
587         int ret = 0, removed;
588 
589         _enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
590 
591         server = afs_server_get_from_peer(call->conn->peer);
592 
593         switch (call->app_call_state) {
594                 /* we've received the last packet - drain all the data from the call */
595         case RXRPC_CSTATE_SRVR_GOT_ARGS:
596                 /* shouldn't be any args */
597                 ret = -EBADMSG;
598                 break;
599 
600                 /* send the reply when asked for it */
601         case RXRPC_CSTATE_SRVR_SND_REPLY:
602                 /* invoke the actual service routine */
603                 ret = SRXAFSCM_Probe(server);
604                 if (ret<0)
605                         break;
606 
607                 ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
608                 if (ret<0)
609                         break;
610                 break;
611 
612                 /* operation complete */
613         case RXRPC_CSTATE_COMPLETE:
614                 call->app_user = NULL;
615                 removed = 0;
616                 spin_lock(&afscm_calls_lock);
617                 if (!list_empty(&call->app_link)) {
618                         list_del_init(&call->app_link);
619                         removed = 1;
620                 }
621                 spin_unlock(&afscm_calls_lock);
622 
623                 if (removed)
624                         rxrpc_put_call(call);
625                 break;
626 
627                 /* operation terminated on error */
628         case RXRPC_CSTATE_ERROR:
629                 call->app_user = NULL;
630                 break;
631 
632         default:
633                 break;
634         }
635 
636         if (ret<0)
637                 rxrpc_call_abort(call,ret);
638 
639         afs_put_server(server);
640 
641         _leave(" = %d",ret);
642 
643 } /* end _SRXAFSCM_Probe() */
644 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp