Whamcloud - gitweb
branch: HEAD
[fs/lustre-release.git] / lustre / ptlrpc / sec_gc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2007 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_SEC
26
27 #ifndef __KERNEL__
28 #include <liblustre.h>
29 #endif
30
31 #include <obd_support.h>
32 #include <obd_class.h>
33 #include <lustre_net.h>
34 #include <lustre_sec.h>
35
36 #define SEC_GC_INTERVAL (30 * 60)
37
38 #ifdef __KERNEL__
39
40 static DECLARE_MUTEX(sec_gc_mutex);
41 static LIST_HEAD(sec_gc_list);
42 static spinlock_t sec_gc_list_lock = SPIN_LOCK_UNLOCKED;
43
44 static struct ptlrpc_thread sec_gc_thread;
45 static atomic_t sec_gc_wait_del = ATOMIC_INIT(0);
46
47 void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec)
48 {
49         CWARN("add sec %p(%s)\n", sec, sec->ps_policy->sp_name);
50         if (!list_empty(&sec->ps_gc_list)) {
51                 CERROR("sec %p(%s) already in gc list\n",
52                        sec, sec->ps_policy->sp_name);
53                 return;
54         }
55
56         spin_lock(&sec_gc_list_lock);
57         list_add_tail(&sec_gc_list, &sec->ps_gc_list);
58         spin_unlock(&sec_gc_list_lock);
59 }
60
61 void sptlrpc_gc_del_sec(struct ptlrpc_sec *sec)
62 {
63         CWARN("del sec %p(%s)\n", sec, sec->ps_policy->sp_name);
64         if (list_empty(&sec->ps_gc_list))
65                 return;
66
67         might_sleep();
68
69         spin_lock(&sec_gc_list_lock);
70         list_del_init(&sec->ps_gc_list);
71         spin_unlock(&sec_gc_list_lock);
72
73         /* barrier */
74         atomic_inc(&sec_gc_wait_del);
75         mutex_down(&sec_gc_mutex);
76         mutex_up(&sec_gc_mutex);
77         atomic_dec(&sec_gc_wait_del);
78 }
79
80 static void sec_do_gc(struct ptlrpc_sec *sec)
81 {
82         cfs_time_t      now = cfs_time_current_sec();
83
84         if (unlikely(sec->ps_gc_next == 0)) {
85                 CWARN("sec %p(%s) has 0 gc time\n",
86                       sec, sec->ps_policy->sp_name);
87                 return;
88         }
89
90         if (unlikely(sec->ps_policy->sp_cops->gc_ctx == NULL)) {
91                 CWARN("sec %p(%s) is not prepared for gc\n",
92                       sec, sec->ps_policy->sp_name);
93                 return;
94         }
95
96         CWARN("check on sec %p(%s)\n", sec, sec->ps_policy->sp_name);
97         if (time_after(sec->ps_gc_next, now))
98                 return;
99
100         sec->ps_policy->sp_cops->gc_ctx(sec);
101         sec->ps_gc_next = now + sec->ps_gc_interval;
102 }
103
104 static int sec_gc_main(void *arg)
105 {
106         struct ptlrpc_thread *thread = (struct ptlrpc_thread *) arg;
107         struct l_wait_info    lwi;
108
109         cfs_daemonize("sptlrpc_ctx_gc");
110
111         /* Record that the thread is running */
112         thread->t_flags = SVC_RUNNING;
113         cfs_waitq_signal(&thread->t_ctl_waitq);
114
115         while (1) {
116                 struct ptlrpc_sec *sec, *next;
117
118 again:
119                 mutex_down(&sec_gc_mutex);
120                 list_for_each_entry_safe(sec, next, &sec_gc_list, ps_gc_list) {
121                         /*
122                          * if someone is waiting to be deleted, let it
123                          * proceed as soon as possible.
124                          */
125                         if (atomic_read(&sec_gc_wait_del)) {
126                                 CWARN("deletion pending, retry\n");
127                                 mutex_up(&sec_gc_mutex);
128                                 goto again;
129                         }
130
131                         sec_do_gc(sec);
132                 }
133                 mutex_up(&sec_gc_mutex);
134
135                 lwi = LWI_TIMEOUT(SEC_GC_INTERVAL * HZ, NULL, NULL);
136                 l_wait_event(thread->t_ctl_waitq,
137                              thread->t_flags & SVC_STOPPING,
138                              &lwi);
139
140                 if (thread->t_flags & SVC_STOPPING) {
141                         thread->t_flags &= ~SVC_STOPPING;
142                         break;
143                 }
144         }
145
146         thread->t_flags = SVC_STOPPED;
147         cfs_waitq_signal(&thread->t_ctl_waitq);
148         return 0;
149 }
150
151 int sptlrpc_gc_start_thread(void)
152 {
153         struct l_wait_info lwi = { 0 };
154         int                rc;
155
156         /* initialize thread control */
157         memset(&sec_gc_thread, 0, sizeof(sec_gc_thread));
158         cfs_waitq_init(&sec_gc_thread.t_ctl_waitq);
159
160         rc = cfs_kernel_thread(sec_gc_main, &sec_gc_thread,
161                                CLONE_VM | CLONE_FILES);
162         if (rc < 0) {
163                 CERROR("can't start gc thread: %d\n", rc);
164                 return rc;
165         }
166
167         l_wait_event(sec_gc_thread.t_ctl_waitq,
168                      sec_gc_thread.t_flags & SVC_RUNNING, &lwi);
169         return 0;
170 }
171
172 void sptlrpc_gc_stop_thread(void)
173 {
174         struct l_wait_info lwi = { 0 };
175
176         sec_gc_thread.t_flags = SVC_STOPPING;
177         cfs_waitq_signal(&sec_gc_thread.t_ctl_waitq);
178
179         l_wait_event(sec_gc_thread.t_ctl_waitq,
180                      sec_gc_thread.t_flags & SVC_STOPPED, &lwi);
181 }
182
183 #else /* !__KERNEL__ */
184
185 void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec)
186 {
187 }
188 void sptlrpc_gc_del_sec(struct ptlrpc_sec *sec)
189 {
190 }
191 int sptlrpc_gc_start_thread(void)
192 {
193         return 0;
194 }
195 void sptlrpc_gc_stop_thread(void)
196 {
197 }
198
199 #endif /* __KERNEL__ */