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