Whamcloud - gitweb
do LASSERT if *name is not NULL
[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         /* skip non-cross_ref entries if we need cross-ref */
77         if (sd->cross_ref && !(d_type & 128))
78                 RETURN(0);
79
80         if (ino == sd->i_num) {
81                 strncpy(sd->name, name, namlen);
82                 sd->rc = 0;
83                 RETURN(-EINTR); /* break the readdir loop */
84         }
85         RETURN(0);
86 }
87
88 static int scan_name_in_parent(struct lustre_id *pid, struct lustre_id *id,
89                                char *name, int cr)
90 {
91         struct file * file;
92         char *pname;
93         struct scan_dir_data sd;
94         int len, rc = 0;
95         ENTRY;
96
97         len = strlen("__iopen__/") + 10 + 1;
98         OBD_ALLOC(pname, len);
99         if (!pname)
100                 RETURN(-ENOMEM);
101         
102         sprintf(pname, "__iopen__/0x%llx", id_ino(pid));
103
104         file = filp_open(pname, O_RDONLY, 0);
105         if (IS_ERR(file)) {
106                 CERROR("can't open directory %s: %d\n",
107                        pname, (int) PTR_ERR(file));
108                 GOTO(out, rc = PTR_ERR(file));
109         }
110         
111         sd.i_num = id_ino(id);
112         sd.name = name;
113         sd.cross_ref = cr;
114         sd.rc = -ENOENT;
115         rc = vfs_readdir(file, filldir, &sd);
116         if (!rc) 
117                 rc = sd.rc;
118
119         filp_close(file, 0);
120
121 out:
122         OBD_FREE(pname, len);
123         RETURN(rc);
124
125 }
126
127 /* id2pid - given id, get parent id or master id.
128  * @obd:   obd device
129  * @id:    child id to be parsed
130  * @pid:   parent id or master id
131  * @type:  id type
132  */
133 static int 
134 id2pid(struct obd_device *obd, struct lustre_id *id, struct lustre_id *pid, 
135        __u32 *type)
136 {
137         struct dentry *dentry = NULL;
138         struct inode *inode = NULL;
139         struct mea *mea = NULL;
140         int mea_size, rc = 0;
141         ENTRY;
142         
143         dentry = mds_id2dentry(obd, id, NULL);
144         if (IS_ERR(dentry) || !dentry->d_inode) {
145                 CERROR("can't find inode "LPU64"\n", id_ino(id));
146                 if (!IS_ERR(dentry)) l_dput(dentry);
147                 RETURN(-ENOENT);
148         }
149         inode = dentry->d_inode;
150
151         if (S_ISDIR(inode->i_mode)) {
152                 //LASSERT(S_ISDIR(id_type(id)));
153                 rc = mds_md_get_attr(obd, inode, &mea, &mea_size);
154                 if (rc)
155                         GOTO(out, rc);
156                 
157                 if (!mea) {
158                         *type = PP_DIR;
159                         goto read_pid;
160                 } else if (mea && mea->mea_count) {
161                         *type = PP_SPLIT_MASTER;
162                         goto read_pid;
163                 } else {
164                         *type = PP_SPLIT_SLAVE;
165                         *pid = mea->mea_ids[mea->mea_master];
166                         LASSERT(id_fid(pid));
167                 }
168                                 
169         } else {
170                 //LASSERT(!S_ISDIR(id_type(id)));
171                 *type = PP_FILE;
172 read_pid:
173                 rc = mds_read_inode_pid(obd, inode, pid);
174                 if (rc) {
175                         CERROR("can't read parent ino(%lu) rc(%d).\n",
176                                inode->i_ino, rc);
177                         GOTO(out, rc);
178                 }
179         }
180
181         /* Well, if it's dir or master split, we have to check if it's 
182          * a cross-ref dir */
183         if ((*type == PP_DIR || *type == PP_SPLIT_MASTER) &&
184              id_group(id) != id_group(pid))
185                 *type = PP_CROSS_DIR;
186 out:
187         if (mea)
188                 OBD_FREE(mea, mea_size);
189         l_dput(dentry);
190         RETURN(rc);
191 }
192
193 static int local_parse_id(struct obd_device *obd, struct parseid_pkg *pkg)
194 {
195         struct lvfs_run_ctxt saved;
196         int rc = 0, cross_ref = 0;
197         ENTRY;
198
199         pkg->pp_rc = 0;
200         pkg->pp_type = 0;
201         memset(pkg->pp_name, 0, sizeof(pkg->pp_name));
202
203         /* pp_id2 is present, which indicating we want to scan parent 
204          * dir(pp_id2) to find the cross-ref entry(pp_id1) */
205         if (id_fid(&pkg->pp_id2)) {
206                 LASSERT(obd->u.mds.mds_num == id_group(&pkg->pp_id2));
207                 pkg->pp_type = PP_DIR;
208                 cross_ref = 1;                
209         } else {
210                 LASSERT(obd->u.mds.mds_num == id_group(&pkg->pp_id1));
211                 rc = id2pid(obd, &pkg->pp_id1, &pkg->pp_id2, &pkg->pp_type);
212                 if (rc)
213                         GOTO(out, rc);
214         }
215
216         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
217         
218         switch (pkg->pp_type) {
219         case PP_FILE:
220         case PP_DIR:
221         case PP_SPLIT_MASTER:
222                 rc = scan_name_in_parent(&pkg->pp_id2, &pkg->pp_id1,
223                                          pkg->pp_name, cross_ref);
224                 if (rc) 
225                         CERROR("scan "LPU64" in parent failed. rc=%d\n",
226                                id_ino(&pkg->pp_id1), rc);
227                 break;
228         case PP_SPLIT_SLAVE:
229         case PP_CROSS_DIR:
230                 break;
231         default:
232                 CERROR("invalid id\n");
233                 break;
234         }
235
236         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
237 out:
238         pkg->pp_rc = rc;
239         RETURN(rc);
240 }
241
242 static int 
243 local_scan_audit_log(struct obd_device *obd, struct parseid_pkg *pkg);
244
245 int mds_parse_id(struct ptlrpc_request *req)
246 {
247         struct parseid_pkg *pkg, *reppkg;
248         struct obd_device *obd = req->rq_export->exp_obd;
249         int rc = 0, size = sizeof(*reppkg);
250         ENTRY;
251
252         pkg = lustre_swab_reqbuf(req, 0, sizeof(*pkg), 
253                                  lustre_swab_parseid_pkg);
254         if (pkg == NULL)
255                 RETURN(-EPROTO);
256
257         rc = lustre_pack_reply(req, 1, &size, NULL);
258         if (rc)
259                 RETURN(rc);
260         
261         reppkg = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*reppkg));
262         memcpy(reppkg, pkg, sizeof(*reppkg));
263
264         if (reppkg->pp_type == PP_AUDIT_LOG)
265                 rc = local_scan_audit_log(obd, reppkg);
266         else
267                 rc = local_parse_id(obd, reppkg);
268         
269         if (rc)
270                 CERROR("local parseid failed. (rc:%d)\n", rc);
271         RETURN(0);  /* we do need pack reply here */
272 }
273
274 static int parse_id(struct obd_device *obd, struct parseid_pkg *pkg)
275 {
276         int rc = 0;
277         int mds_num = id_group(&pkg->pp_id1);
278         ENTRY;
279         
280         //for cross-ref dir we should send request to parent's MDS
281         if (pkg->pp_type == PP_CROSS_DIR)
282                 mds_num = id_group(&pkg->pp_id2);
283         
284         LASSERT(mds_num >= 0);
285
286         if (mds_num == obd->u.mds.mds_num) {
287                 rc = local_parse_id(obd, pkg);
288         } else {
289                 struct ptlrpc_request *req;
290                 struct lmv_obd *lmv = &obd->u.mds.mds_md_obd->u.lmv;
291                 struct parseid_pkg *body;
292                 int size = sizeof(*body);
293                 struct obd_export *exp;
294                 
295                 /* make sure connection established */
296                 rc = obd_set_info(obd->u.mds.mds_md_exp, strlen("chkconnect"),
297                                   "chkconnect", 0, NULL);
298                 if (rc)
299                         RETURN(rc);
300
301                 exp = lmv->tgts[mds_num].ltd_exp;
302                 LASSERTF(exp, "No export for MDS #%i\n", mds_num);
303
304                 req = ptlrpc_prep_req(class_exp2cliimp(exp), 
305                                       LUSTRE_MDS_VERSION, MDS_PARSE_ID, 1, 
306                                       &size, NULL);
307                 if (!req)
308                         RETURN(-ENOMEM);
309
310                 body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
311                 memcpy(body, pkg, sizeof(*body));
312                 
313                 req->rq_replen = lustre_msg_size(1, &size);
314
315                 rc = ptlrpc_queue_wait(req);
316                 if (rc)
317                         GOTO(out, rc);
318
319                 body = lustre_swab_repbuf(req, 0, sizeof(*body), 
320                                           lustre_swab_parseid_pkg);
321                 if (body == NULL) {
322                         CERROR("can't unpack parseid_pkg\n");
323                         GOTO(out, rc = -EPROTO);
324                 }
325                 memcpy(pkg, body, sizeof(*pkg));
326 out:
327                 ptlrpc_req_finished(req);
328         }
329         RETURN(rc);
330 }
331
332 #define ROOT_FID        2
333 struct name_item {
334         struct list_head link;
335         char             name[NAME_MAX + 1];
336 };
337
338 int 
339 mds_id2name(struct obd_device *obd, struct lustre_id *id, 
340             struct list_head *list, struct lustre_id *lastid)
341 {
342         struct name_item *item;
343         struct parseid_pkg *pkg;
344         int rc = 0;
345         ENTRY;
346
347         OBD_ALLOC(pkg, sizeof(*pkg));
348         if (pkg == NULL)
349                 RETURN(-ENOMEM);
350
351         pkg->pp_id1 = *id;
352         while (id_fid(&pkg->pp_id1) != ROOT_FID) {
353                 
354                 rc = parse_id(obd, pkg);
355                 if (rc) {
356                         CDEBUG(D_SEC, "parse id failed. rc=%d\n", rc);
357                         *lastid = pkg->pp_id1;
358                         break;
359                 }
360
361                 switch (pkg->pp_type) {
362                 case PP_FILE:
363                 case PP_DIR:
364                 case PP_SPLIT_MASTER:
365                         OBD_ALLOC(item, sizeof(*item));
366                         if (item == NULL)
367                                 GOTO(out, rc = -ENOMEM);
368                         
369                         INIT_LIST_HEAD(&item->link);
370                         list_add(&item->link, list);
371                         memcpy(item->name, pkg->pp_name, sizeof(item->name));
372
373                 case PP_SPLIT_SLAVE:
374                         pkg->pp_id1 = pkg->pp_id2;
375                         memset(&pkg->pp_id2, 0, sizeof(struct lustre_id));
376                 case PP_CROSS_DIR:
377                         break;
378                 default:
379                         CERROR("Wrong id = %i\n", pkg->pp_type);
380                         break;
381                 }
382                 
383         }
384 out:
385         OBD_FREE(pkg, sizeof(*pkg));
386         RETURN(rc);
387 }
388
389 static int
390 scan_audit_log_cb(struct llog_handle *llh, struct llog_rec_hdr *rec, void *data)
391 {
392         struct parseid_pkg *pkg = (struct parseid_pkg *)data;
393         struct audit_record *ad_rec; 
394         struct audit_id_record *cid_rec, *pid_rec;
395         struct audit_name_record *nm_rec;
396         ENTRY;
397
398         if (!(le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN)) {
399                 CERROR("log is not plain\n");
400                 RETURN(-EINVAL);
401         }
402         
403         if (rec->lrh_type != SMFS_AUDIT_NAME_REC)
404                 RETURN(0);
405         
406         ad_rec = (struct audit_record *)(rec + 1);
407         if (ad_rec->result ||
408             (ad_rec->opcode != AUDIT_UNLINK &&
409              ad_rec->opcode != AUDIT_RENAME))
410                 RETURN(0);
411
412         cid_rec = (struct audit_id_record *)(ad_rec + 1);
413         pid_rec = cid_rec + 1;
414         nm_rec = (struct audit_name_record *)(pid_rec + 1);
415                 
416         if (cid_rec->au_num == id_ino(&pkg->pp_id1) &&
417             cid_rec->au_gen == id_gen(&pkg->pp_id1)) {
418                 LASSERT(pid_rec->au_fid);
419                 /* get parent id */
420                 id_ino(&pkg->pp_id2) = pid_rec->au_num;
421                 id_gen(&pkg->pp_id2) = pid_rec->au_gen;
422                 id_type(&pkg->pp_id2) = pid_rec->au_type;
423                 id_fid(&pkg->pp_id2) = pid_rec->au_fid;
424                 id_group(&pkg->pp_id2) = pid_rec->au_mds;
425                 /* get name */
426                 memcpy(pkg->pp_name, nm_rec->name, 
427                        le32_to_cpu(nm_rec->name_len));
428                 RETURN(LLOG_PROC_BREAK);
429         }
430         RETURN(0);
431 }
432
433 static int
434 local_scan_audit_log(struct obd_device *obd, struct parseid_pkg *pkg)
435 {
436         struct llog_handle *llh = NULL;
437         struct llog_ctxt *ctxt = llog_get_context(&obd->obd_llogs,
438                                                   LLOG_AUDIT_ORIG_CTXT);
439         int rc = 0;
440         ENTRY;
441
442         pkg->pp_rc = 0;
443         if (ctxt)
444                 llh = ctxt->loc_handle;
445
446         if (llh == NULL)
447                 GOTO(out, rc = -ENOENT);
448
449         rc = llog_cat_process(llh, (llog_cb_t)&scan_audit_log_cb, (void *)pkg);
450         if (rc != LLOG_PROC_BREAK) {
451                 CWARN("process catalog log failed: rc(%d)\n", rc);
452                 rc = -ENOENT;
453         } else {
454                 rc = 0;
455         }
456 out:
457         pkg->pp_rc = rc;
458         RETURN(rc);
459 }
460
461 static int 
462 scan_audit_log(struct obd_device *obd, struct lustre_id *cur_id, 
463                struct list_head *list, struct lustre_id *parent_id)
464 {
465         struct name_item *item = NULL;
466         int rc = 0, mds_num = id_group(cur_id);
467         struct parseid_pkg *pkg = NULL;
468         ENTRY;
469
470         OBD_ALLOC(pkg, sizeof(*pkg));
471         if (pkg == NULL)
472                 RETURN(-ENOMEM);
473
474         pkg->pp_type = PP_AUDIT_LOG;
475         pkg->pp_id1 = *cur_id;
476
477         if (obd->u.mds.mds_num == mds_num) {
478                 rc = local_scan_audit_log(obd, pkg);
479         } else {
480                 struct ptlrpc_request *req;
481                 struct lmv_obd *lmv = &obd->u.mds.mds_md_obd->u.lmv;
482                 struct parseid_pkg *body;
483                 int size = sizeof(*body);
484                 struct obd_export *exp;
485                 
486                 /* make sure connection established */
487                 rc = obd_set_info(obd->u.mds.mds_md_exp, strlen("chkconnect"),
488                                   "chkconnect", 0, NULL);
489                 if (rc)
490                         RETURN(rc);
491
492                 exp = lmv->tgts[mds_num].ltd_exp;
493                 LASSERTF(exp, "No export for MDS #%i\n", mds_num);
494
495                 req = ptlrpc_prep_req(class_exp2cliimp(exp), 
496                                       LUSTRE_MDS_VERSION, MDS_PARSE_ID, 1, 
497                                       &size, NULL);
498                 if (!req)
499                         RETURN(-ENOMEM);
500
501                 body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
502                 memcpy(body, pkg, sizeof(*body));
503                 
504                 req->rq_replen = lustre_msg_size(1, &size);
505
506                 rc = ptlrpc_queue_wait(req);
507                 if (rc)
508                         GOTO(out_req, rc);
509
510                 body = lustre_swab_repbuf(req, 0, sizeof(*body), 
511                                           lustre_swab_parseid_pkg);
512                 if (body == NULL) {
513                         CERROR("can't unpack parseid_pkg\n");
514                         GOTO(out, rc = -EPROTO);
515                 }
516                 memcpy(pkg, body, sizeof(*pkg));
517 out_req:
518                 ptlrpc_req_finished(req);
519
520         }
521
522         if (!rc) rc = pkg->pp_rc;
523         if (rc)
524                 GOTO(out, rc);
525         
526         *parent_id = pkg->pp_id2;
527
528         OBD_ALLOC(item, sizeof(*item));
529         if (item == NULL)
530                 GOTO(out, rc = -ENOMEM);
531         
532         INIT_LIST_HEAD(&item->link);
533         list_add(&item->link, list);
534         memcpy(item->name, pkg->pp_name, sizeof(item->name));
535 out:
536         OBD_FREE(pkg, sizeof(*pkg));
537         RETURN(rc);
538 }
539        
540 int 
541 mds_audit_id2name(struct obd_device *obd, char **name, int *namelen, 
542                   struct lustre_id *id)
543 {
544         int rc = 0;
545         struct list_head list, *pos, *n;
546         struct name_item *item;
547         struct lustre_id parent_id, cur_id;
548         ENTRY;
549
550         *namelen = 0;
551         INIT_LIST_HEAD(&list);
552
553         cur_id = *id;
554         if (!id_ino(&cur_id)) {
555                 CERROR("Invalid id!\n");
556                 RETURN(-EINVAL);
557         }
558         if (id_fid(&cur_id) == ROOT_FID)
559                 RETURN(0);
560         
561 next:
562         memset(&parent_id, 0, sizeof(parent_id));
563         rc = mds_id2name(obd, &cur_id, &list, &parent_id);
564         if (rc == -ENOENT) {
565                 /* can't reconstruct name from id, turn to audit log */
566                 cur_id = parent_id;
567                 memset(&parent_id, 0, sizeof(parent_id));
568
569                 rc = scan_audit_log(obd, &cur_id, &list, &parent_id);
570                 if (rc) {
571                         CERROR("scan id in audit log failed. (rc:%d)\n", rc);
572                         GOTO(out, rc);
573                 }
574
575                 LASSERT(id_fid(&parent_id));
576                 cur_id = parent_id;
577                 goto next;
578
579         } else if (rc) {
580                 CERROR("reconstruct name from id failed. (rc:%d)\n", rc);
581                 GOTO(out, rc);
582         }
583         
584         list_for_each_safe (pos, n, &list) {
585                 item = list_entry(pos, struct name_item, link);
586                 *namelen += strlen(item->name) + 1;
587         }
588         
589         (*namelen)++;     /* for the ending '\0' of string */
590         OBD_ALLOC(*name, *namelen);
591         if (*name == NULL)
592                 rc = -ENOMEM;
593 out:
594         list_for_each_safe (pos, n, &list) {
595                 item = list_entry(pos, struct name_item, link);
596                 
597                 if (!rc) {
598                         strcat(*name, "/");
599                         strcat(*name, item->name);
600                 }
601                 list_del_init(&item->link);
602                 OBD_FREE(item, sizeof(*item));
603                 if (*name)
604                         LASSERT(strlen(*name) < *namelen);
605         }
606         RETURN(rc);
607 }
608 EXPORT_SYMBOL(mds_audit_id2name);