Whamcloud - gitweb
b=8654
[fs/lustre-release.git] / lustre / mds / mds_audit_path.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *
5  *  Copyright (C) 2001-2003 Cluster File Systems, Inc.
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #ifndef EXPORT_SYMTAB
24 # define EXPORT_SYMTAB
25 #endif
26 #define DEBUG_SUBSYSTEM S_MDS
27
28 #include <linux/module.h>
29 #include <linux/lustre_mds.h>
30 #include <linux/lustre_dlm.h>
31 #include <linux/lustre_fsfilt.h>
32 #include <linux/init.h>
33 #include <linux/obd_class.h>
34 #include <linux/fs.h>
35 #include <linux/namei.h>
36 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
37 # include <linux/smp_lock.h>
38 # include <linux/buffer_head.h>
39 # include <linux/workqueue.h>
40 # include <linux/mount.h>
41 #else
42 # include <linux/locks.h>
43 #endif
44 #include <linux/lustre_audit.h>
45 #include "mds_internal.h"
46
47
48 #define PP_FILE         1
49 #define PP_DIR          2
50 #define PP_SPLIT_MASTER 3
51 #define PP_SPLIT_SLAVE  4
52 #define PP_CROSS_DIR    5
53 #define PP_AUDIT_LOG    6       /* search id in audit log */
54
55 struct scan_dir_data {
56         int               rc;
57         __u32            i_num;
58         __u8             cross_ref;
59         char             *name;
60 };
61
62 static int filldir(void *__buf, const char *name, int namlen,
63                    loff_t offset, ino_t ino, unsigned int d_type)
64 {
65         struct scan_dir_data *sd = __buf;
66         ENTRY;
67
68         if (name[0] == '.' &&
69             (namlen == 1 || (namlen == 2 && name[1] == '.'))) {
70                 /* skip special entries */
71                 RETURN(0);
72         }
73
74         LASSERT(sd != NULL);
75
76         if (ino == sd->i_num) {
77                 strncpy(sd->name, name, namlen);
78                 sd->rc = 0;
79                 RETURN(-EINTR); /* break the readdir loop */
80         }
81         RETURN(0);
82 }
83
84 static int scan_name_in_parent(struct lustre_id *pid, struct lustre_id *id,
85                                char *name, int cr)
86 {
87         struct file * file;
88         char *pname;
89         struct scan_dir_data sd;
90         int len, rc = 0;
91         ENTRY;
92
93         len = strlen("__iopen__/") + 10 + 1;
94         OBD_ALLOC(pname, len);
95         if (!pname)
96                 RETURN(-ENOMEM);
97         
98         sprintf(pname, "__iopen__/0x%llx", id_ino(pid));
99
100         file = filp_open(pname, O_RDONLY, 0);
101         if (IS_ERR(file)) {
102                 CERROR("can't open directory %s: %d\n",
103                        pname, (int) PTR_ERR(file));
104                 GOTO(out, rc = PTR_ERR(file));
105         }
106         
107         sd.i_num = id_ino(id);
108         sd.name = name;
109         sd.cross_ref = cr;
110         sd.rc = -ENOENT;
111         vfs_readdir(file, filldir, &sd);
112
113         filp_close(file, 0);
114         rc = sd.rc;
115
116 out:
117         OBD_FREE(pname, len);
118         RETURN(rc);
119
120 }
121
122 /* id2pid - given id, get parent id or master id.
123  * @obd:   obd device
124  * @id:    child id to be parsed
125  * @pid:   parent id or master id
126  * @type:  id type
127  */
128 static int 
129 id2pid(struct obd_device *obd, struct lustre_id *id, struct lustre_id *pid, 
130        __u32 *type)
131 {
132         struct dentry *dentry = NULL;
133         struct inode *inode = NULL;
134         struct mea *mea = NULL;
135         int mea_size, rc = 0;
136         ENTRY;
137         
138         dentry = mds_id2dentry(obd, id, NULL);
139         if (IS_ERR(dentry) || !dentry->d_inode) {
140                 CERROR("can't find inode "LPU64"\n", id_ino(id));
141                 if (!IS_ERR(dentry)) l_dput(dentry);
142                 RETURN(-ENOENT);
143         }
144         inode = dentry->d_inode;
145
146         if (S_ISDIR(inode->i_mode)) {
147                 //LASSERT(S_ISDIR(id_type(id)));
148                 rc = mds_md_get_attr(obd, inode, &mea, &mea_size);
149                 if (rc)
150                         GOTO(out, rc);
151                 
152                 if (!mea) {
153                         *type = PP_DIR;
154                         goto read_pid;
155                 } else if (mea && mea->mea_count) {
156                         *type = PP_SPLIT_MASTER;
157                         goto read_pid;
158                 } else {
159                         *type = PP_SPLIT_SLAVE;
160                         *pid = mea->mea_ids[mea->mea_master];
161                 }
162                                 
163         } else {
164                 //LASSERT(!S_ISDIR(id_type(id)));
165                 *type = PP_FILE;
166 read_pid:
167                 rc = mds_read_inode_pid(obd, inode, pid);
168                 if (rc) {
169                         CERROR("can't read parent ino(%lu) rc(%d).\n",
170                                inode->i_ino, rc);
171                         GOTO(out, rc);
172                 }
173         }
174
175         /* Well, if it's dir or master split, we have to check if it's 
176          * a cross-ref dir */
177         if ((*type == PP_DIR || *type == PP_SPLIT_MASTER) &&
178              id_group(id) != id_group(pid))
179                 *type = PP_CROSS_DIR;
180 out:
181         if (mea)
182                 OBD_FREE(mea, mea_size);
183         l_dput(dentry);
184         RETURN(rc);
185 }
186
187 static int local_parse_id(struct obd_device *obd, struct parseid_pkg *pkg)
188 {
189         struct lvfs_run_ctxt saved;
190         int rc = 0, cross_ref = 0;
191         ENTRY;
192
193         pkg->pp_rc = 0;
194         pkg->pp_type = 0;
195         memset(pkg->pp_name, 0, sizeof(pkg->pp_name));
196
197         //LASSERT(obd->u.mds.mds_num == id_group(&pkg->pp_id1));
198
199         /* pp_id2 is present, which indicating we want to scan parent 
200          * dir(pp_id2) to find the cross-ref entry(pp_id1) */
201         if (id_fid(&pkg->pp_id2)) {
202                 pkg->pp_type = PP_DIR;
203                 cross_ref = 1;                
204         } else {
205                 rc = id2pid(obd, &pkg->pp_id1, &pkg->pp_id2, &pkg->pp_type);
206                 if (rc)
207                         GOTO(out, rc);
208         }
209
210         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
211         
212         switch (pkg->pp_type) {
213         case PP_FILE:
214         case PP_DIR:
215         case PP_SPLIT_MASTER:
216                 rc = scan_name_in_parent(&pkg->pp_id2, &pkg->pp_id1,
217                                          pkg->pp_name, cross_ref);
218                 if (rc) 
219                         CERROR("scan "LPU64" in parent failed. rc=%d\n",
220                                id_ino(&pkg->pp_id1), rc);
221                 break;
222         case PP_SPLIT_SLAVE:
223         case PP_CROSS_DIR:
224                 break;
225         default:
226                 CERROR("invalid id\n");
227                 break;
228         }
229
230         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
231 out:
232         pkg->pp_rc = rc;
233         RETURN(rc);
234 }
235
236 static int 
237 local_scan_audit_log(struct obd_device *obd, struct parseid_pkg *pkg);
238
239 int mds_parse_id(struct ptlrpc_request *req)
240 {
241         struct parseid_pkg *pkg, *reppkg;
242         struct obd_device *obd = req->rq_export->exp_obd;
243         int rc = 0, size = sizeof(*reppkg);
244         ENTRY;
245
246         pkg = lustre_swab_reqbuf(req, 0, sizeof(*pkg), 
247                                  lustre_swab_parseid_pkg);
248         if (pkg == NULL)
249                 RETURN(-EPROTO);
250
251         rc = lustre_pack_reply(req, 1, &size, NULL);
252         if (rc)
253                 RETURN(rc);
254         
255         reppkg = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*reppkg));
256         memcpy(reppkg, pkg, sizeof(*reppkg));
257
258         if (reppkg->pp_type == PP_AUDIT_LOG)
259                 rc = local_scan_audit_log(obd, reppkg);
260         else
261                 rc = local_parse_id(obd, reppkg);
262         
263         if (rc)
264                 CERROR("local parseid failed. (rc:%d)\n", rc);
265         RETURN(0);  /* we do need pack reply here */
266 }
267
268 static int parse_id(struct obd_device *obd, struct parseid_pkg *pkg)
269 {
270         int rc = 0;
271         int mds_num = id_group(&pkg->pp_id1);
272         ENTRY;
273         
274         LASSERT(mds_num >= 0);
275
276         //for cross-ref dir we should send request to parent's MDS
277         if (pkg->pp_type == PP_CROSS_DIR)
278                 mds_num = id_group(&pkg->pp_id2);
279         
280         if (mds_num == obd->u.mds.mds_num) {
281                 rc = local_parse_id(obd, pkg);
282         } else {
283                 struct ptlrpc_request *req;
284                 struct lmv_obd *lmv = &obd->u.mds.mds_md_obd->u.lmv;
285                 struct parseid_pkg *body;
286                 int size = sizeof(*body);
287                 struct obd_export *exp;
288                 
289                 /* make sure connection established */
290                 rc = obd_set_info(obd->u.mds.mds_md_exp, strlen("chkconnect"),
291                                   "chkconnect", 0, NULL);
292                 if (rc)
293                         RETURN(rc);
294
295                 exp = lmv->tgts[mds_num].ltd_exp;
296                 LASSERT(exp);
297
298                 req = ptlrpc_prep_req(class_exp2cliimp(exp), 
299                                       LUSTRE_MDS_VERSION, MDS_PARSE_ID, 1, 
300                                       &size, NULL);
301                 if (!req)
302                         RETURN(-ENOMEM);
303
304                 body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
305                 memcpy(body, pkg, sizeof(*body));
306                 
307                 req->rq_replen = lustre_msg_size(1, &size);
308
309                 rc = ptlrpc_queue_wait(req);
310                 if (rc)
311                         GOTO(out, rc);
312
313                 body = lustre_swab_repbuf(req, 0, sizeof(*body), 
314                                           lustre_swab_parseid_pkg);
315                 if (body == NULL) {
316                         CERROR("can't unpack parseid_pkg\n");
317                         GOTO(out, rc = -EPROTO);
318                 }
319                 memcpy(pkg, body, sizeof(*pkg));
320 out:
321                 ptlrpc_req_finished(req);
322         }
323         RETURN(rc);
324 }
325
326 #define ROOT_FID        2
327 struct name_item {
328         struct list_head link;
329         char             name[NAME_MAX + 1];
330 };
331
332 int 
333 mds_id2name(struct obd_device *obd, struct lustre_id *id, 
334             struct list_head *list, struct lustre_id *lastid)
335 {
336         struct name_item *item;
337         struct parseid_pkg *pkg;
338         int rc = 0;
339         ENTRY;
340
341         OBD_ALLOC(pkg, sizeof(*pkg));
342         if (pkg == NULL)
343                 RETURN(-ENOMEM);
344
345         pkg->pp_id1 = *id;
346         while (id_fid(&pkg->pp_id1) != ROOT_FID) {
347                 
348                 rc = parse_id(obd, pkg);
349                 if (rc) {
350                         CDEBUG(D_SEC, "parse id failed. rc=%d\n", rc);
351                         *lastid = pkg->pp_id1;
352                         break;
353                 }
354
355                 switch (pkg->pp_type) {
356                 case PP_FILE:
357                 case PP_DIR:
358                 case PP_SPLIT_MASTER:
359                         OBD_ALLOC(item, sizeof(*item));
360                         if (item == NULL)
361                                 GOTO(out, rc = -ENOMEM);
362                         
363                         INIT_LIST_HEAD(&item->link);
364                         list_add(&item->link, list);
365                         memcpy(item->name, pkg->pp_name, sizeof(item->name));
366                         
367                 case PP_SPLIT_SLAVE:
368                         pkg->pp_id1 = pkg->pp_id2;
369                         memset(&pkg->pp_id2, 0, sizeof(struct lustre_id));
370                 case PP_CROSS_DIR:
371                         break;
372                 default:
373                         CERROR("Wrong id = %i\n", pkg->pp_type);
374                         break;
375                 }
376                 
377         }
378 out:
379         OBD_FREE(pkg, sizeof(*pkg));
380         RETURN(rc);
381 }
382
383 static int
384 scan_audit_log_cb(struct llog_handle *llh, struct llog_rec_hdr *rec, void *data)
385 {
386         struct parseid_pkg *pkg = (struct parseid_pkg *)data;
387         struct audit_record *ad_rec; 
388         struct audit_id_record *cid_rec, *pid_rec;
389         struct audit_name_record *nm_rec;
390         ENTRY;
391
392         if (!(le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN)) {
393                 CERROR("log is not plain\n");
394                 RETURN(-EINVAL);
395         }
396         if (rec->lrh_type != SMFS_AUDIT_NAME_REC &&
397             rec->lrh_type != LLOG_GEN_REC) {
398                 RETURN(0);
399         }
400
401         ad_rec = (struct audit_record *)((char *)rec + sizeof(*rec));
402
403         if (ad_rec->result || 
404             ad_rec->opcode != AUDIT_UNLINK ||
405             ad_rec->opcode != AUDIT_RENAME)
406                 RETURN(0);
407
408         cid_rec = (struct audit_id_record *)((char *)ad_rec + sizeof(*ad_rec));
409         pid_rec = cid_rec + 1;
410         nm_rec = (struct audit_name_record *)
411                 ((char *)pid_rec + sizeof(*pid_rec));
412         
413         if (cid_rec->au_num == id_ino(&pkg->pp_id1) &&
414             cid_rec->au_gen == id_gen(&pkg->pp_id1)) {
415                 /* get parent id */
416                 id_ino(&pkg->pp_id2) = pid_rec->au_num;
417                 id_gen(&pkg->pp_id2) = pid_rec->au_gen;
418                 id_type(&pkg->pp_id2) = pid_rec->au_type;
419                 id_fid(&pkg->pp_id2) = pid_rec->au_fid;
420                 id_group(&pkg->pp_id2) = pid_rec->au_mds;
421                 /* get name */
422                 memcpy(pkg->pp_name, nm_rec->name, 
423                        le32_to_cpu(nm_rec->name_len));
424
425                 RETURN(LLOG_PROC_BREAK);
426         }
427         RETURN(0);
428 }
429
430 static int
431 local_scan_audit_log(struct obd_device *obd, struct parseid_pkg *pkg)
432 {
433         struct llog_handle *llh = NULL;
434         struct llog_ctxt *ctxt = llog_get_context(&obd->obd_llogs,
435                                                   LLOG_AUDIT_ORIG_CTXT);
436         int rc = 0;
437         ENTRY;
438
439         if (ctxt)
440                 llh = ctxt->loc_handle;
441
442         if (llh == NULL)
443                 RETURN(-ENOENT);
444
445         rc = llog_cat_process(llh, (llog_cb_t)&scan_audit_log_cb, (void *)pkg);
446         if (rc != LLOG_PROC_BREAK) {
447                 CWARN("process catalog log failed: rc(%d)\n", rc);
448                 RETURN(-ENOENT);
449         }
450         RETURN(0);
451 }
452
453 static int 
454 scan_audit_log(struct obd_device *obd, struct lustre_id *cur_id, 
455                struct list_head *list, struct lustre_id *parent_id)
456 {
457         struct name_item *item = NULL;
458         int rc = 0, mds_num = id_group(cur_id);
459         struct parseid_pkg *pkg = NULL;
460         ENTRY;
461
462         OBD_ALLOC(pkg, sizeof(*pkg));
463         if (pkg == NULL)
464                 RETURN(-ENOMEM);
465
466         pkg->pp_type = PP_AUDIT_LOG;
467         pkg->pp_id1 = *cur_id;
468
469         if (obd->u.mds.mds_num == mds_num) {
470                 rc = local_scan_audit_log(obd, pkg);
471         } else {
472                 struct ptlrpc_request *req;
473                 struct lmv_obd *lmv = &obd->u.mds.mds_md_obd->u.lmv;
474                 struct parseid_pkg *body;
475                 int size = sizeof(*body);
476                 struct obd_export *exp;
477                 
478                 /* make sure connection established */
479                 rc = obd_set_info(obd->u.mds.mds_md_exp, strlen("chkconnect"),
480                                   "chkconnect", 0, NULL);
481                 if (rc)
482                         RETURN(rc);
483
484                 exp = lmv->tgts[mds_num].ltd_exp;
485                 LASSERT(exp);
486
487                 req = ptlrpc_prep_req(class_exp2cliimp(exp), 
488                                       LUSTRE_MDS_VERSION, MDS_PARSE_ID, 1, 
489                                       &size, NULL);
490                 if (!req)
491                         RETURN(-ENOMEM);
492
493                 body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
494                 memcpy(body, pkg, sizeof(*body));
495                 
496                 req->rq_replen = lustre_msg_size(1, &size);
497
498                 rc = ptlrpc_queue_wait(req);
499                 if (rc)
500                         GOTO(out_req, rc);
501
502                 body = lustre_swab_repbuf(req, 0, sizeof(*body), 
503                                           lustre_swab_parseid_pkg);
504                 if (body == NULL) {
505                         CERROR("can't unpack parseid_pkg\n");
506                         GOTO(out, rc = -EPROTO);
507                 }
508                 memcpy(pkg, body, sizeof(*pkg));
509 out_req:
510                 ptlrpc_req_finished(req);
511
512         }
513
514         if (!rc) rc = pkg->pp_rc;
515         if (rc)
516                 GOTO(out, rc);
517         
518         *parent_id = pkg->pp_id2;
519
520         OBD_ALLOC(item, sizeof(*item));
521         if (item == NULL)
522                 GOTO(out, rc = -ENOMEM);
523         
524         INIT_LIST_HEAD(&item->link);
525         list_add(&item->link, list);
526         memcpy(item->name, pkg->pp_name, sizeof(item->name));
527 out:
528         OBD_FREE(pkg, sizeof(*pkg));
529         RETURN(rc);
530 }
531        
532 int 
533 mds_audit_id2name(struct obd_device *obd, char **name, int *namelen, 
534                   struct lustre_id *id)
535 {
536         int rc = 0;
537         struct list_head list, *pos, *n;
538         struct name_item *item;
539         struct lustre_id parent_id, cur_id;
540         ENTRY;
541
542         *namelen = 0;
543         INIT_LIST_HEAD(&list);
544
545         cur_id = *id;
546         if (id_fid(&cur_id) == ROOT_FID)
547                 RETURN(0);
548 next:
549         memset(&parent_id, 0, sizeof(parent_id));
550         rc = mds_id2name(obd, &cur_id, &list, &parent_id);
551         if (rc == -ENOENT) {
552                 /* can't reconstruct name from id, turn to audit log */
553                 LASSERT(id_fid(&parent_id));
554                 cur_id = parent_id;
555                 memset(&parent_id, 0, sizeof(parent_id));
556
557                 rc = scan_audit_log(obd, &cur_id, &list, &parent_id);
558                 if (rc) {
559                         CERROR("scan id in audit log failed. (rc:%d)\n", rc);
560                         GOTO(out, rc);
561                 }
562
563                 LASSERT(id_fid(&parent_id));
564                 cur_id = parent_id;
565                 goto next;
566
567         } else if (rc) {
568                 CERROR("reconstruct name from id failed. (rc:%d)\n", rc);
569                 GOTO(out, rc);
570         }
571         
572         list_for_each_safe (pos, n, &list) {
573                 item = list_entry(pos, struct name_item, link);
574                 *namelen += strlen(item->name) + 1;
575         }
576         OBD_ALLOC(*name, *namelen);
577         if (*name == NULL)
578                 rc = -ENOMEM;
579 out:
580         list_for_each_safe (pos, n, &list) {
581                 item = list_entry(pos, struct name_item, link);
582                 if (!rc) {
583                         strcat(*name, "/");
584                         strcat(*name, item->name);
585                 }
586                 list_del_init(&item->link);
587                 OBD_FREE(item, sizeof(*item));
588         }
589         RETURN(rc);
590 }
591 EXPORT_SYMBOL(mds_audit_id2name);