Whamcloud - gitweb
d9714308d58fc267abeb2ec009a30add7ca9a503
[fs/lustre-release.git] / lustre / smfs / audit_transfer.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/smfs/audit_transfer.c
5  *
6  *  Copyright (C) 2004 Cluster File Systems, Inc.
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 #ifndef EXPORT_SYMTAB
24 # define EXPORT_SYMTAB
25 #endif
26
27 #define DEBUG_SUBSYSTEM S_SM
28
29 #include <linux/fs.h>
30 #include <linux/slab.h>
31 #include <linux/obd_class.h>
32 #include <linux/obd_support.h>
33 #include <linux/lustre_lib.h>
34 #include <linux/lustre_idl.h>
35 #include <linux/lustre_fsfilt.h>
36 #include <linux/lustre_smfs.h>
37 #include <linux/lustre_audit.h>
38 #include <linux/lustre_log.h>
39 #include "smfs_internal.h"
40
41 struct transfer_item {
42         struct llog_handle      *ti_llh;
43         struct list_head        ti_link;
44         void * id2name;
45 };
46
47 #define TRANSFERD_STOP          0
48 struct transferd_ctl {
49         unsigned long           tc_flags;
50         wait_queue_head_t       tc_waitq;
51         struct completion       tc_starting;
52         struct completion       tc_stopping;
53
54         struct list_head        tc_list;
55         spinlock_t              tc_lock;
56 };
57
58 static struct transferd_ctl transferd_tc;
59 static DECLARE_MUTEX(transferd_sem);
60 static int transferd_users = 0;
61 char *buf = NULL;
62
63 static int transferd_check(struct transferd_ctl *tc)
64 {
65         int rc = 0;
66         ENTRY;
67         
68         if (test_bit(TRANSFERD_STOP, &tc->tc_flags))
69                 RETURN(1);
70         
71         spin_lock(&tc->tc_lock);
72         rc = list_empty(&tc->tc_list) ? 0 : 1;
73         spin_unlock(&tc->tc_lock);
74         
75         RETURN(rc);
76 }
77
78 int audit_notify(struct llog_handle *llh, void * arg)
79 {
80         struct transfer_item *ti;
81         struct list_head tmp_list;
82         ENTRY;
83
84         down(&transferd_sem);
85         if (transferd_users == 0) {
86                 up(&transferd_sem);
87                 RETURN(0);
88         }
89         up(&transferd_sem);
90
91         if (test_bit(TRANSFERD_STOP, &transferd_tc.tc_flags)) {
92                 CDEBUG(D_INFO, "transfer daemon stopped\n");
93                 RETURN(0);
94         }
95
96         OBD_ALLOC(ti, sizeof(*ti));
97         if (ti == NULL)
98                 RETURN(-ENOMEM);
99         
100         INIT_LIST_HEAD(&ti->ti_link);
101         ti->ti_llh = llh;
102         ti->id2name = arg;
103
104         spin_lock(&transferd_tc.tc_lock);
105         list_add_tail(&ti->ti_link, &transferd_tc.tc_list);
106         spin_unlock(&transferd_tc.tc_lock);
107
108         wake_up(&transferd_tc.tc_waitq);
109         
110         if (llh == NULL) /* demand to flush list */
111         {
112                 struct l_wait_info lwi = { 0 };
113                 l_wait_event(transferd_tc.tc_waitq,
114                              transferd_check(&transferd_tc), &lwi);
115         }
116
117         RETURN(0);
118 }
119                                                                                                                                                
120 const char *opstr[AUDIT_MAX] = {
121         [AUDIT_UNKNOWN]  "unknown",
122         [AUDIT_CREATE]   "create",
123         [AUDIT_LINK]     "link",
124         [AUDIT_UNLINK]   "unlink",
125         [AUDIT_RENAME]   "rename",
126         [AUDIT_SETATTR]  "setattr",
127         [AUDIT_WRITE]    "write",
128         [AUDIT_READ]     "read",
129         [AUDIT_OPEN]     "open",
130         [AUDIT_STAT]     "stat",
131         [AUDIT_MMAP]     "mmap",
132         [AUDIT_READLINK] "readlink",
133         [AUDIT_READDIR]  "readdir",
134 };
135
136 #define construct_header(buf, size, rec, id_rec)                        \
137         snprintf(buf, size, "AUDIT:"LPX64":%u/%u:%s:%d:"DLID4":",       \
138         rec->nid, rec->uid, rec->gid, opstr[rec->opcode], (__s16)rec->result,\
139         (unsigned long)id_rec->au_fid, (unsigned long)id_rec->au_mds, \
140         (unsigned long)id_rec->au_num, (unsigned long)id_rec->au_gen);
141
142 #define REC2ID(rec, id) {                                       \
143         id_ino(id) = rec->au_num;                               \
144         id_gen(id) = rec->au_gen;                               \
145         id_type(id) = rec->au_type;                             \
146         id_fid(id) = rec->au_fid;                               \
147         id_group(id) = rec->au_mds;                             \
148 }
149
150 static int 
151 transfer_record(struct obd_device *obd, struct audit_record *rec, int type, void * data)
152 {
153         struct audit_id_record *id_rec = 
154                 (struct audit_id_record *)(rec + 1);
155         struct audit_name_record *name_rec = NULL;
156         int (*audit_id2name)(struct obd_device *obd, char **name, 
157                      int *namelen, struct lustre_id *id) = data;
158
159         int n, rc = 0;
160         ENTRY;
161
162         CDEBUG(D_INFO, "transfer %s\n", opstr[rec->opcode]);
163
164         memset(buf, 0, PAGE_SIZE);
165         n = construct_header(buf, PAGE_SIZE, rec, id_rec);
166         if (n < 0)
167                 RETURN(n);
168         /* let's use remaining space */
169         n = PAGE_SIZE - n;
170         
171         switch (rec->opcode)
172         {
173                 case AUDIT_UNLINK:
174                         if (type != SMFS_AUDIT_NAME_REC)
175                                 break;
176                 case AUDIT_LINK:
177                 case AUDIT_RENAME:
178                         id_rec++;
179                 default:
180                         break;
181         }
182         
183         if (audit_id2name) {
184                 char *name = NULL;
185                 struct lustre_id id;
186                 int namelen = 0;
187         
188                 REC2ID(id_rec, &id);
189                 
190                 //LASSERT(id_type(&id) & S_IFMT);
191                 rc = audit_id2name(obd, &name, &namelen, &id);
192                 if (rc < 0) {
193                         strncat(buf, "unknown", n);
194                         n -= strlen("unknown");
195                 } else if (namelen == 0) {
196                         //root itself
197                         if (type != SMFS_AUDIT_NAME_REC)
198                                 strcat(buf, "/");
199                 } else {
200                         strncat(buf, name, n);
201                         n -= namelen;
202                         OBD_FREE(name, namelen);
203                 } 
204         }
205
206         if (type == SMFS_AUDIT_NAME_REC && n > 0) {
207                 name_rec = (struct audit_name_record *)(++id_rec);
208                 strcat(buf, "/");
209                 n -= 1;
210                 /* get minimum size to copy name with exact len */
211                 if (n > name_rec->name_len)
212                         n = name_rec->name_len; 
213                 strncat(buf, name_rec->name, n);
214         }
215         
216         CDEBUG(D_INFO, "%s\n", buf);
217
218         printk("%s\n", buf);
219
220         RETURN(0);
221 }
222
223 static int transfer_cb(struct llog_handle *llh, struct llog_rec_hdr *rec,
224                        void *data)
225 {
226         struct obd_device *obd = llh->lgh_ctxt->loc_obd;
227         struct audit_record *ad_rec;
228         struct llog_cookie cookie;
229         ENTRY;
230         
231         if (!(le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN)) {
232                 CERROR("log is not plain\n");
233                 RETURN(-EINVAL);
234         }
235         if (rec->lrh_type != cpu_to_le32(SMFS_AUDIT_GEN_REC) &&
236             rec->lrh_type != cpu_to_le32(SMFS_AUDIT_NAME_REC)) {
237                 CERROR("log record type error\n");
238                 RETURN(-EINVAL);
239         }
240
241         ad_rec = (struct audit_record *)((char *)rec + sizeof(*rec));
242         
243         LASSERT(ad_rec->opcode < AUDIT_MAX);
244
245         cookie.lgc_lgl = llh->lgh_id;
246         cookie.lgc_subsys = LLOG_AUDIT_ORIG_CTXT;
247         cookie.lgc_index = le32_to_cpu(rec->lrh_index);
248
249         transfer_record(obd, ad_rec, rec->lrh_type, data);
250         
251         llog_cancel(llh->lgh_ctxt, 1, &cookie, 0, NULL);
252
253         RETURN(0);
254 }
255
256 static int audit_transfer(struct transfer_item *ti)
257 {
258         struct llog_handle *llh = ti->ti_llh;
259         int rc = 0;
260         ENTRY;
261         
262         if (!llh)
263                 RETURN(0);
264
265         rc = llog_cat_process(llh, (llog_cb_t)&transfer_cb, ti->id2name);
266         if (rc)
267                 CERROR("process catalog log failed: rc(%d)\n", rc);
268
269         RETURN(0);
270 }
271
272 static int transferd(void *arg)
273 {
274         struct transferd_ctl *tc = arg;
275         unsigned long flags;
276         struct list_head *pos, *tmp;
277         struct transfer_item *ti = NULL;
278         ENTRY;
279
280         lock_kernel();
281         
282         /* ptlrpc_daemonize() */
283         exit_mm(current);
284         lustre_daemonize_helper();
285         exit_files(current);
286         reparent_to_init();
287         
288         SIGNAL_MASK_LOCK(current, flags);
289         sigfillset(&current->blocked);
290         RECALC_SIGPENDING;
291         SIGNAL_MASK_UNLOCK(current, flags);
292         THREAD_NAME(current->comm, sizeof(current->comm) - 1, "%s", 
293                     "audit_transferd");
294         unlock_kernel();
295
296         complete(&tc->tc_starting);
297
298         LASSERT(buf == NULL);
299         OBD_ALLOC(buf, PAGE_SIZE);
300         LASSERT(buf != NULL);
301
302         while (1) {
303                 struct l_wait_info lwi = { 0 };
304                 
305                 l_wait_event(tc->tc_waitq, transferd_check(tc), &lwi);
306                 
307                 if (test_bit(TRANSFERD_STOP, &tc->tc_flags))
308                         break;
309                 
310                 spin_lock(&tc->tc_lock);
311                 LASSERT(!list_empty(&tc->tc_list));
312                 ti = list_entry(tc->tc_list.next, struct transfer_item, ti_link);
313                 list_del_init(&ti->ti_link);
314                 spin_unlock(&tc->tc_lock);
315                 
316                 audit_transfer(ti);
317                 OBD_FREE(ti, sizeof(*ti));
318
319         }
320
321         OBD_FREE(buf, PAGE_SIZE);
322
323         spin_lock(&tc->tc_lock);
324         list_for_each_safe(pos, tmp, &tc->tc_list) {
325                 ti = list_entry(pos, struct transfer_item, ti_link);
326                 list_del_init(&ti->ti_link);
327                 OBD_FREE(ti, sizeof(*ti));
328         }
329         spin_unlock(&tc->tc_lock);
330
331         complete(&tc->tc_stopping);
332         RETURN(0);
333 }
334
335 int audit_start_transferd()
336 {
337         int rc = 0;
338         ENTRY;
339         
340         down(&transferd_sem);
341         if (++transferd_users != 1)
342                 GOTO(out, rc = 0);
343
344         memset(&transferd_tc, 0, sizeof(transferd_tc));
345         init_completion(&transferd_tc.tc_starting);
346         init_completion(&transferd_tc.tc_stopping);
347         init_waitqueue_head(&transferd_tc.tc_waitq);
348         transferd_tc.tc_flags = 0;
349         INIT_LIST_HEAD(&transferd_tc.tc_list);
350         spin_lock_init(&transferd_tc.tc_lock);
351         
352         if (kernel_thread(transferd, &transferd_tc, 0) < 0) {
353                 transferd_users--;
354                 GOTO(out, rc = -ECHILD);
355         }
356
357         wait_for_completion(&transferd_tc.tc_starting);
358 out:
359         up(&transferd_sem);
360         RETURN(rc);
361 }
362
363 int audit_stop_transferd(void)
364 {
365         int rc = 0;
366         ENTRY;
367
368         down(&transferd_sem);
369         if (--transferd_users > 0)
370                 GOTO(out, rc = 0);
371
372         set_bit(TRANSFERD_STOP, &transferd_tc.tc_flags);
373         wake_up(&transferd_tc.tc_waitq);
374         wait_for_completion(&transferd_tc.tc_stopping);
375 out:
376         up(&transferd_sem);
377         RETURN(rc);
378 }