Whamcloud - gitweb
Land b_hd_capa onto HEAD (20050809_1942)
[fs/lustre-release.git] / lustre / mds / mds_capa.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004, 2005 Cluster File Systems, Inc.
5  *
6  * Author: Lai Siyao <lsy@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #define DEBUG_SUBSYSTEM S_MDS
25
26 #include <linux/fs.h>
27 #include <linux/version.h>
28 #include <asm/uaccess.h>
29 #include <linux/file.h>
30 #include <linux/kmod.h>
31 #include <linux/random.h>
32
33 #include <linux/obd.h>
34 #include <linux/lustre_mds.h>
35 #include <linux/lustre_fsfilt.h>
36 #include <linux/lustre_sec.h>
37
38 #include "mds_internal.h"
39
40 static struct ptlrpc_thread mds_eck_thread;
41
42 static struct thread_ctl {
43         struct completion ctl_starting;
44         struct completion ctl_finishing;
45 } mds_eck_ctl;
46
47 static LIST_HEAD(mds_capa_key_list);
48 static LIST_HEAD(mds_expired_capa_keys);
49 static spinlock_t mds_capa_lock; /* protect capa and capa key */
50 struct timer_list mds_eck_timer;
51
52 #define CUR_MDS_CAPA_KEY(mds) mds->mds_capa_keys[mds->mds_capa_key_idx]
53 #define CUR_CAPA_KEY(mds) CUR_MDS_CAPA_KEY(mds).k_key
54 #define CUR_CAPA_KEY_ID(mds) CUR_MDS_CAPA_KEY(mds).k_key->lk_keyid
55 #define CUR_CAPA_KEY_EXPIRY(mds) expiry_to_jiffies(CUR_CAPA_KEY(mds)->lk_expiry)
56 #define CUR_CAPA_KEY_LIST(mds) CUR_MDS_CAPA_KEY(mds).k_list
57
58 static int mds_write_capa_key(struct obd_device *obd, int force_sync)
59 {
60         struct mds_obd *mds = &obd->u.mds;
61         struct mds_capa_key *keys = mds->mds_capa_keys;
62         struct file *filp = mds->mds_capa_keys_filp;
63         struct lvfs_run_ctxt saved;
64         loff_t off = 0;
65         int i, rc;
66         ENTRY;
67
68         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
69         for (i = 0; i < 2 && keys[i].k_key; i++) {
70                 rc = fsfilt_write_record(obd, filp, keys[i].k_key,
71                                          sizeof(*keys[i].k_key),
72                                          &off, force_sync);
73                 if (rc) {
74                         CERROR("error writing MDS capa key: rc = %d\n", rc);
75                         break;
76                 }
77         }
78         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
79
80         RETURN(rc);
81 }
82
83 static inline int
84 mds_capa_key_cmp(struct mds_obd *mds)
85 {
86         return capa_key_cmp(mds->mds_capa_keys[0].k_key,
87                             mds->mds_capa_keys[1].k_key);
88 }
89
90 static void
91 do_update_capa_key(struct mds_obd *mds, struct lustre_capa_key *key)
92 {
93         __u32 keyid = 1;
94         __u64 expiry_rounded;
95
96         if (CUR_CAPA_KEY(mds))
97                 keyid = le32_to_cpu(CUR_CAPA_KEY(mds)->lk_keyid) + 1;
98         expiry_rounded = round_expiry(mds->mds_capa_key_timeout);
99
100         key->lk_mdsid = cpu_to_le32(mds->mds_num);
101         key->lk_keyid = cpu_to_le32(keyid);
102         key->lk_expiry = cpu_to_le64(expiry_rounded);
103         get_random_bytes(key->lk_key, sizeof(key->lk_key));
104 }
105
106 static void list_add_capa_key(struct mds_capa_key *key, struct list_head *head)
107 {
108         struct mds_capa_key *tmp;
109
110         list_for_each_entry_reverse(tmp, head, k_list) {
111                 if (key->k_key->lk_expiry > tmp->k_key->lk_expiry) {
112                         list_add(&key->k_list, &tmp->k_list);
113                         return;
114                 }
115         }
116
117         list_add(&key->k_list, head);
118 }
119
120 int mds_read_capa_key(struct obd_device *obd, struct file *file)
121 {
122         loff_t off = 0;
123         struct mds_obd *mds = &obd->u.mds;
124         struct lustre_capa_key *key;
125         unsigned long capa_keys_size = file->f_dentry->d_inode->i_size;
126         int i = 0, rc = 0;
127         ENTRY;
128
129         if (capa_keys_size == 0) {
130                 CWARN("%s: initializing new %s\n", obd->obd_name,
131                       file->f_dentry->d_name.name);
132                  
133                 OBD_ALLOC(key, sizeof(*key));
134                 if (!key)
135                         RETURN(-ENOMEM);
136
137                 do_update_capa_key(mds, key);
138
139                 mds->mds_capa_keys[0].k_key = key;
140                 mds->mds_capa_keys[0].k_obd = obd;
141                 INIT_LIST_HEAD(&mds->mds_capa_keys[0].k_list);
142                 mds->mds_capa_key_idx = 0;
143
144                 rc = mds_write_capa_key(obd, 1);
145                 if (rc)
146                         GOTO(out, rc);
147         } else {
148                 LASSERT(capa_keys_size == sizeof(*key) ||
149                         capa_keys_size == 2 * sizeof(*key));
150
151                 while (capa_keys_size > i * sizeof(*key)) {
152                         OBD_ALLOC(key, sizeof(*key));
153                         if (!key)
154                                 RETURN(-ENOMEM);
155
156                         rc = fsfilt_read_record(obd, file, key, sizeof(*key),
157                                                 &off);
158                         if (rc) {
159                                 CERROR("error reading MDS %s capa key: %d\n",
160                                        file->f_dentry->d_name.name, rc);
161                                 OBD_FREE(key, sizeof(*key));
162                                 GOTO(out, rc);
163                         }
164
165                         mds->mds_capa_keys[i].k_key = key;
166                         mds->mds_capa_keys[i].k_obd = obd;
167                         INIT_LIST_HEAD(&mds->mds_capa_keys[i].k_list);
168                         i++;
169                 }
170
171                 mds->mds_capa_key_idx = 0;
172                 if (mds->mds_capa_keys[1].k_key && mds_capa_key_cmp(mds) < 0)
173                         mds->mds_capa_key_idx = 1;
174         }
175
176         spin_lock(&mds_capa_lock);
177         if (time_before(CUR_CAPA_KEY_EXPIRY(mds), mds_eck_timer.expires)
178             || !timer_pending(&mds_eck_timer))
179                 mod_timer(&mds_eck_timer, CUR_CAPA_KEY_EXPIRY(mds));
180
181         list_add_capa_key(&CUR_MDS_CAPA_KEY(mds), &mds_capa_key_list);
182         spin_unlock(&mds_capa_lock);
183 out:
184         RETURN(rc);
185 }
186
187 void mds_capa_keys_cleanup(struct obd_device *obd)
188 {
189         struct mds_obd *mds = &obd->u.mds;
190         int i;
191
192         spin_lock(&mds_capa_lock);
193         if (CUR_CAPA_KEY(mds))
194                 list_del_init(&CUR_CAPA_KEY_LIST(mds));
195         spin_unlock(&mds_capa_lock);
196
197         for (i = 0; i < 2; i++)
198                 if (mds->mds_capa_keys[i].k_key)
199                         OBD_FREE(mds->mds_capa_keys[i].k_key,
200                                  sizeof(struct lustre_capa_key));
201 }
202
203 static int mds_set_capa_key(struct obd_device *obd, struct lustre_capa_key *key)
204 {
205         struct mds_obd *mds = &obd->u.mds;
206         int rc;
207         ENTRY;
208
209         rc = obd_set_info(mds->mds_dt_exp, strlen("capa_key"), "capa_key",
210                           sizeof(*key), key);
211         if (rc)
212                 CERROR("obd_set_info capa_key failed: rc = %d\n", rc);
213
214         RETURN(rc);
215 }
216
217 static int
218 mds_update_capa_key(struct obd_device *obd, struct mds_capa_key *mkey,
219                     int force_sync)
220 {
221         struct mds_obd *mds = &obd->u.mds;
222         int to_update = mds->mds_capa_key_idx ^ 1;
223         struct lustre_capa_key *key = mds->mds_capa_keys[to_update].k_key;
224         __u32 keyid;
225         int rc = 0;
226         ENTRY;
227
228         LASSERT(mkey != &mds->mds_capa_keys[to_update]);
229
230         if (key == NULL) {
231                 /* first update */
232                 OBD_ALLOC(key, sizeof(*key));
233                 if (!key)
234                         RETURN(-ENOMEM);
235                 mds->mds_capa_keys[to_update].k_key = key;
236                 mds->mds_capa_keys[to_update].k_obd = obd;
237         }
238
239         do_update_capa_key(mds, key);
240
241         keyid = le32_to_cpu(key->lk_keyid);
242
243         rc = mds_set_capa_key(obd, key);
244         if (rc) {
245                 CERROR("error set capa key(id %u), err = %d\n", keyid, rc);
246                 GOTO(out, rc);
247         }
248
249         CDEBUG(D_INFO, "MDS capa_keyid is %u\n", keyid);
250
251         rc = mds_write_capa_key(obd, 1);
252         if (rc)
253                 GOTO(out, rc);
254         
255         CDEBUG(D_INFO, "wrote capa keyid %u: err = %d\n", keyid, rc);
256
257         spin_lock(&mds_capa_lock);
258         list_del_init(&CUR_CAPA_KEY_LIST(mds));
259         mds->mds_capa_key_idx = to_update;
260         list_add_capa_key(&CUR_MDS_CAPA_KEY(mds), &mds_capa_key_list);
261         spin_unlock(&mds_capa_lock);
262
263         /* TODO: update timer here */
264 out:
265         RETURN(rc);
266 }
267
268 static inline int have_expired_capa_key(void)
269 {
270         struct mds_capa_key *key;
271         int expired = 0;
272         ENTRY;
273
274         spin_lock(&mds_capa_lock);
275         if (!list_empty(&mds_capa_key_list)) {
276                 key = list_entry(mds_capa_key_list.next, struct mds_capa_key,
277                                  k_list);
278                 expired = time_before(expiry_to_jiffies(key->k_key->lk_expiry),
279                                       jiffies);
280         }
281         spin_unlock(&mds_capa_lock);
282
283         RETURN(expired);
284 }
285
286 static int inline mds_capa_key_check_stop(void)
287 {
288         return (mds_eck_thread.t_flags & SVC_STOPPING) ? 1: 0;
289 }
290
291 static int mds_capa_key_thread_main(void *arg)
292 {
293         struct thread_ctl *ctl = arg;
294         unsigned long flags;
295         ENTRY;
296
297         {
298                 char name[sizeof(current->comm)];
299                 snprintf(name, sizeof(name) - 1, "mds_ck");
300                 kportal_daemonize(name);
301         }
302
303         SIGNAL_MASK_LOCK(current, flags);
304         sigfillset(&current->blocked);
305         RECALC_SIGPENDING;
306         SIGNAL_MASK_UNLOCK(current, flags);
307
308         /*
309          * letting starting function know, that we are ready and control may be
310          * returned.
311          */
312         mds_eck_thread.t_flags = SVC_RUNNING;
313         complete(&ctl->ctl_starting);
314
315         while (!mds_capa_key_check_stop()) {
316                 struct l_wait_info lwi = { 0 };
317                 struct mds_capa_key *key, *tmp, *next = NULL;
318
319                 l_wait_event(mds_eck_thread.t_ctl_waitq,
320                              (have_expired_capa_key() ||
321                               mds_capa_key_check_stop()),
322                              &lwi);
323
324                 spin_lock(&mds_capa_lock);
325                 list_for_each_entry_safe(key, tmp, &mds_capa_key_list, k_list) {
326                         if (time_after(expiry_to_jiffies(key->k_key->lk_expiry),
327                                        jiffies)) {
328                                 next = key;
329                                 break;
330                         }
331
332                         spin_unlock(&mds_capa_lock);
333
334                         CDEBUG(D_INFO, "mds capa key expired, wake up updating "
335                                        "thread: mds #%u, key #%u\n",
336                                le32_to_cpu(key->k_key->lk_mdsid),
337                                le32_to_cpu(key->k_key->lk_keyid));
338
339                         mds_update_capa_key(key->k_obd, key, 1);
340                         spin_lock(&mds_capa_lock);
341                 }
342
343                 if (next)
344                         mod_timer(&mds_eck_timer,
345                                   expiry_to_jiffies(next->k_key->lk_expiry));
346                 spin_unlock(&mds_capa_lock);
347         }
348
349         mds_eck_thread.t_flags = SVC_STOPPED;
350
351         /* this is SMP-safe way to finish thread. */
352         complete_and_exit(&ctl->ctl_finishing, 0);
353         EXIT;
354 }
355
356 void mds_capa_key_timer_callback(unsigned long unused)
357 {
358         ENTRY;
359         wake_up(&mds_eck_thread.t_ctl_waitq);
360         EXIT;
361 }
362
363 int mds_capa_key_start_thread(void)
364 {
365         int rc;
366         ENTRY;
367
368         LASSERT(mds_eck_thread.t_flags == 0);
369         init_completion(&mds_eck_ctl.ctl_starting);
370         init_completion(&mds_eck_ctl.ctl_finishing);
371         init_waitqueue_head(&mds_eck_thread.t_ctl_waitq);
372         spin_lock_init(&mds_capa_lock);
373
374         rc = kernel_thread(mds_capa_key_thread_main, &mds_eck_ctl,
375                            (CLONE_VM | CLONE_FILES));
376         if (rc < 0) {
377                 CERROR("cannot start capa key thread, "
378                        "err = %d\n", rc);
379                 RETURN(rc);
380         }
381
382         wait_for_completion(&mds_eck_ctl.ctl_starting);
383         LASSERT(mds_eck_thread.t_flags == SVC_RUNNING);
384         RETURN(0);
385 }
386
387 void mds_capa_key_stop_thread(void)
388 {
389         ENTRY;
390         mds_eck_thread.t_flags = SVC_STOPPING;
391         wake_up(&mds_eck_thread.t_ctl_waitq);
392         wait_for_completion(&mds_eck_ctl.ctl_finishing);
393         LASSERT(mds_eck_thread.t_flags == SVC_STOPPED);
394         mds_eck_thread.t_flags = 0;
395         EXIT;
396 }
397
398 int mds_pack_capa(struct obd_device *obd, struct mds_body *req_body,
399                   struct lustre_capa *req_capa, struct lustre_msg *repmsg,
400                   int *offset, struct mds_body *body)
401 {
402         struct mds_obd *mds = &obd->u.mds;
403         struct lustre_capa *capa;
404         struct obd_capa *ocapa;
405         __u8 key[CAPA_KEY_LEN];  /* key */
406         int expired, rc = 0;
407         ENTRY;
408
409         if (mds->mds_capa_stat == 0) {
410                 (*offset)++;
411                 RETURN(0); /* capability is disabled */
412         }
413
414         if (OBD_FAIL_CHECK(OBD_FAIL_MDS_PACK_CAPA))
415                 RETURN(-EINVAL);
416
417         if (req_body) {
418                 /* capa renewal, check capa op against open mode */
419                 struct mds_file_data *mfd;
420                 int mode;
421
422                 mfd = mds_handle2mfd(&req_body->handle);
423                 if (mfd == NULL) {
424                         CERROR("no handle for capa renewal ino "LPD64
425                                ": cookie "LPX64"\n",
426                                req_capa->lc_ino, req_body->handle.cookie);
427                         RETURN(-ESTALE);
428                 }
429
430                 mode = accmode(mfd->mfd_mode);
431                 if (!(req_capa->lc_op & mode)) {
432                         CERROR("invalid capa to renew ino "LPD64
433                                ": op %d mismatch with mode %d\n",
434                                req_capa->lc_ino, req_capa->lc_op, mfd->mfd_mode);
435                         RETURN(-EACCES);
436                 }
437         }
438
439         LASSERT(repmsg->buflens[*offset] == sizeof(*capa));
440         capa = lustre_msg_buf(repmsg, (*offset)++, sizeof(*capa));
441         LASSERT(capa != NULL);
442
443         ocapa = capa_get(req_capa->lc_uid, req_capa->lc_op, req_capa->lc_mdsid,
444                          req_capa->lc_ino, MDS_CAPA, NULL, NULL, NULL);
445         if (ocapa) {
446                 expired = capa_is_to_expire(ocapa);
447                 if (!expired) {
448                         capa_dup(capa, ocapa);
449                         capa_put(ocapa, MDS_CAPA);
450                         GOTO(out, rc);
451                 }
452                 capa_put(ocapa, MDS_CAPA);
453         }
454
455         memcpy(capa, req_capa, sizeof(*capa));
456
457         spin_lock(&mds_capa_lock);
458         capa->lc_keyid = le32_to_cpu(CUR_CAPA_KEY_ID(mds));
459         capa->lc_expiry = round_expiry(mds->mds_capa_timeout);
460         if (mds->mds_capa_timeout < CAPA_EXPIRY)
461                 capa->lc_flags |= CAPA_FL_NOROUND;
462         memcpy(key, CUR_CAPA_KEY(mds)->lk_key, sizeof(key));
463         spin_unlock(&mds_capa_lock);
464
465         capa_hmac(mds->mds_capa_hmac, key, capa);
466
467         rc = capa_renew(capa, MDS_CAPA);
468 out:
469         if (rc == 0)
470                 body->valid |= OBD_MD_CAPA;
471         RETURN(rc);
472 }