Whamcloud - gitweb
- numerous fixes from b_cray, b_1_4 and Andreas' comments.
[fs/lustre-release.git] / lustre / lvfs / lvfs_reint.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2004 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25
26 #define DEBUG_SUBSYSTEM S_FILTER
27
28 #include <linux/version.h>
29 #include <linux/fs.h>
30 #include <asm/unistd.h>
31 #include <linux/jbd.h>
32 #include <linux/slab.h>
33 #include <linux/pagemap.h>
34 #include <linux/quotaops.h>
35 #include <linux/version.h>
36 #include <libcfs/kp30.h>
37 #include <linux/lustre_fsfilt.h>
38 #include <linux/obd.h>
39 #include <linux/obd_class.h>
40 #include <linux/module.h>
41 #include <linux/init.h>
42 #include <linux/lustre_compat25.h>
43 #include <linux/lvfs.h>
44 #include <linux/lustre_smfs.h>
45 #include "lvfs_internal.h"
46
47 #include <linux/obd.h>
48 #include <linux/lustre_lib.h>
49
50 int lookup_by_path(char *path, int flags, struct nameidata *nd)
51 {
52         struct dentry *dentry = NULL;
53         int rc = 0;
54         
55 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
56         if (path_init(path, flags, nd)) {
57 #else
58         if (path_lookup(path, flags, nd)) {
59 #endif
60                 rc = path_walk(path, nd);
61                 if (rc)
62                         RETURN(rc);
63         } else
64                 RETURN(-EINVAL);
65
66         dentry = nd->dentry;
67
68         if (!dentry->d_inode || is_bad_inode(dentry->d_inode) || 
69             (!S_ISDIR(dentry->d_inode->i_mode))) { 
70                 path_release(nd);
71                 RETURN(-ENODEV);
72         }
73         RETURN(rc); 
74 }  
75
76 struct dentry *lookup_create(struct nameidata *nd, int is_dir)
77 {
78         struct dentry *dentry;
79
80         dentry = ERR_PTR(-EEXIST);
81         if (nd->last_type != LAST_NORM)
82                 goto fail;
83         dentry = lookup_hash(&nd->last, nd->dentry);
84         if (IS_ERR(dentry))
85                 goto fail;
86         if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
87                 goto enoent;
88         return dentry;
89 enoent:
90         dput(dentry);
91         dentry = ERR_PTR(-ENOENT);
92 fail:
93         return dentry;
94 }
95
96 static int lvfs_reint_create(struct super_block *sb, struct reint_record *r_rec)
97 {
98         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
99         char *path = r_rec->name.path_name;
100         int type = r_rec->u_rec.ur_iattr.ia_mode & S_IFMT;
101         struct nameidata nd;
102         struct dentry *dparent = NULL;
103         struct dentry *dentry = NULL;
104         struct inode *dir = NULL;
105         void *handle = NULL;
106         int rc = 0, created = 0, err = 0;
107         ENTRY;
108
109         rc = lookup_by_path(path, LOOKUP_PARENT, &nd);
110         if (rc)
111                 RETURN(rc);
112
113         dparent = nd.dentry;
114
115         down(&dparent->d_inode->i_sem);
116         /*create a new dentry*/
117         dentry = lookup_create(&nd, 0);
118         dir = dparent->d_inode;
119
120         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
121                 SMFS_CLEAN_INODE_REC(dir);
122
123         switch(type) {
124         case S_IFREG:
125                 handle = fsfilt->fs_start(dir, FSFILT_OP_CREATE, NULL, 0);
126                 if (IS_ERR(handle))
127                         GOTO(cleanup, rc = PTR_ERR(handle));
128                 rc = ll_vfs_create(dir, dentry, r_rec->u_rec.ur_iattr.ia_mode,
129                                    NULL);
130                 break;
131         case S_IFDIR:
132                 handle = fsfilt->fs_start(dir, FSFILT_OP_MKDIR, NULL, 0);
133                 if (IS_ERR(handle))
134                         GOTO(cleanup, rc = PTR_ERR(handle));
135                 rc = vfs_mkdir(dir, dentry, r_rec->u_rec.ur_iattr.ia_mode);
136                 break;
137         case S_IFLNK: {
138                 char *new_path = r_rec->u.re_name.path_name;
139                 handle = fsfilt->fs_start(dir, FSFILT_OP_SYMLINK, NULL, 0);
140                 if (IS_ERR(handle))
141                         GOTO(cleanup, rc = PTR_ERR(handle));
142                 rc = ll_vfs_symlink(dir, dentry, new_path, S_IALLUGO);
143                 break;
144         }
145         case S_IFCHR:
146         case S_IFBLK:
147         case S_IFIFO:
148         case S_IFSOCK: {
149                 int rdev = r_rec->u_rec.ur_rdev;
150                 handle = fsfilt->fs_start(dir, FSFILT_OP_MKNOD, NULL, 0);
151                 if (IS_ERR(handle))
152                         GOTO(cleanup, (handle = NULL, rc = PTR_ERR(handle)));
153                 rc = vfs_mknod(dir, dentry, r_rec->u_rec.ur_iattr.ia_mode,
154                                rdev);
155                 break;
156         }
157         default:
158                 CERROR("Error type %d in create\n", type);
159                 rc = -EINVAL;
160                 break;
161         }
162
163         if (rc) {
164                 CERROR("Error for creating mkdir %s\n", path);
165                 GOTO(cleanup, 0);
166         } else {
167                 struct iattr iattr;
168
169                 created = 1;
170
171                 LTIME_S(iattr.ia_atime) =
172                         LTIME_S(r_rec->u_rec.ur_iattr.ia_atime);
173                 LTIME_S(iattr.ia_ctime) =
174                         LTIME_S(r_rec->u_rec.ur_iattr.ia_ctime);
175                 LTIME_S(iattr.ia_mtime) =
176                         LTIME_S(r_rec->u_rec.ur_iattr.ia_mtime);
177
178                 iattr.ia_uid = r_rec->u_rec.ur_fsuid;
179                 if (dir->i_mode & S_ISGID)
180                         iattr.ia_gid = dir->i_gid;
181                 else
182                         iattr.ia_gid = r_rec->u_rec.ur_fsgid;
183                 iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_ATIME |
184                         ATTR_MTIME | ATTR_CTIME;
185
186                 rc = fsfilt->fs_setattr(dentry, handle, &iattr, 0);
187                 if (rc) {
188                         CERROR("error on child setattr: rc = %d\n", rc);
189                         GOTO(cleanup, rc);
190                 }
191
192                 iattr.ia_valid = ATTR_MTIME | ATTR_CTIME;
193                 rc = fsfilt->fs_setattr(dparent, handle, &iattr, 0);
194                 if (rc) {
195                         CERROR("error on parent setattr: rc = %d\n", rc);
196                         GOTO(cleanup, rc);
197                 }
198         }
199 cleanup:
200         if (rc && created) {
201                 /* Destroy the file we just created.  This should not need
202                  * extra journal credits, as we have already modified all of
203                  * the blocks needed in order to create the file in the first
204                  * place.
205                  */
206                 switch (type) {
207                 case S_IFDIR:
208                         err = vfs_rmdir(dir, dentry);
209                         if (err)
210                                 CERROR("rmdir in error path: %d\n", err);
211                         break;
212                 default:
213                         err = vfs_unlink(dir, dentry);
214                         if (err)
215                                 CERROR("unlink in error path: %d\n", err);
216                         break;
217                 }
218         } else {
219                 rc = err;
220         }
221         if (handle)
222                 rc = fsfilt->fs_commit(dentry->d_inode, handle, 0);
223
224         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
225                 SMFS_SET_INODE_REC(dir);
226         up(&dparent->d_inode->i_sem);
227         path_release(&nd);
228         if (dentry)
229                 l_dput(dentry);
230
231         RETURN(0);
232 };
233
234 static int lvfs_reint_link(struct super_block *sb, struct reint_record *r_rec)
235 {
236         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
237         char   *old_path = r_rec->name.path_name;
238         char   *new_path = r_rec->u.re_name.path_name;
239         struct nameidata old_nd;
240         struct nameidata new_nd;
241         struct dentry *old_dparent;
242         struct dentry *new_dparent;
243         struct dentry *old_dentry = NULL;
244         struct dentry *new_dentry = NULL;
245         void   *handle = NULL;
246         struct inode *dir = NULL;
247         int    rc = 0;
248         ENTRY;
249
250         /*get parent dentry*/
251         rc = lookup_by_path(new_path, LOOKUP_PARENT, &new_nd);
252         if (rc)
253                 RETURN(rc);
254
255         new_dparent = new_nd.dentry;
256
257         dir = new_dparent->d_inode;
258
259         new_dentry = lookup_create(&new_nd, 0);
260
261         rc = lookup_by_path(old_path, LOOKUP_PARENT, &old_nd);
262         if (rc) {
263                 path_release(&new_nd);
264                 RETURN(rc);
265         }
266         old_dparent = old_nd.dentry;
267         old_dentry = lookup_one_len(old_nd.last.name, old_dparent,
268                                     old_nd.last.len);
269
270         if (IS_ERR(old_dentry) || !old_dentry->d_inode ||
271             is_bad_inode(old_dentry->d_inode))
272                 GOTO(cleanup, rc = -ENODEV);
273         if (dir->i_rdev != old_dentry->d_inode->i_rdev)
274                 GOTO(cleanup, rc = -EINVAL);
275
276         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
277                 SMFS_CLEAN_INODE_REC(dir);
278
279         handle = fsfilt->fs_start(dir, FSFILT_OP_LINK, NULL, 0);
280         if (IS_ERR(handle))
281                 GOTO(cleanup, rc = PTR_ERR(handle));
282
283         rc = vfs_link(old_dentry, dir, new_dentry);
284         if (rc) {
285                 CERROR("replay error: vfs_link error rc=%d", rc);
286                 GOTO(cleanup, rc);
287         }
288 cleanup:
289         if (handle)
290                 rc = fsfilt->fs_commit(dir, handle, 0);
291         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
292                 SMFS_SET_INODE_REC(dir);
293         if (old_dentry)
294                 l_dput(old_dentry);
295         if (new_dentry)
296                 l_dput(new_dentry);
297         path_release(&new_nd);
298         path_release(&old_nd);
299         RETURN(rc);
300 };
301
302 static int lvfs_reint_unlink(struct super_block *sb, struct reint_record *r_rec)
303 {
304         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
305         int type = r_rec->u_rec.ur_iattr.ia_mode & S_IFMT;
306         char *path = r_rec->name.path_name;
307         struct nameidata nd;
308         struct dentry *dparent = NULL;
309         struct dentry *dentry = NULL;
310         struct inode *dir = NULL;
311         void *handle = NULL;
312         int rc = 0;
313         ENTRY;
314
315         rc = lookup_by_path(path, LOOKUP_PARENT, &nd);
316         if (rc)
317                 RETURN(rc);
318
319         dparent = nd.dentry;
320
321         dir = dparent->d_inode;
322
323         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);
324         if (IS_ERR(dentry) || !dentry->d_inode || is_bad_inode(dentry->d_inode))
325                 GOTO(cleanup, rc = -ENODEV);
326
327         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
328                 SMFS_CLEAN_INODE_REC(dir);
329
330         handle = fsfilt->fs_start(dir, FSFILT_OP_UNLINK, NULL, 0);
331
332         if (IS_ERR(handle))
333                 GOTO(cleanup, rc = PTR_ERR(handle));
334
335         switch (type) {
336         case S_IFDIR:
337                 rc = vfs_rmdir(dir, dentry);
338                 if (rc)
339                         CERROR("rmdir in error path: %d\n", rc);
340                 break;
341         default:
342                 rc = vfs_unlink(dir, dentry);
343                 if (rc)
344                         CERROR("unlink in error path: %d\n", rc);
345                 break;
346         }
347         if (!rc) {
348                 /*time attr of dir inode*/
349                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
350
351                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
352                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
353                 if (rc) {
354                         CERROR("error on parent setattr: rc = %d\n", rc);
355                         GOTO(cleanup, rc);
356                 }
357         }
358 cleanup:
359         if (handle)
360                 fsfilt->fs_commit(dir, handle, 0);
361         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
362                 SMFS_SET_INODE_REC(dir);
363         if (dentry)
364                 l_dput(dentry);
365         path_release(&nd);
366         RETURN(rc);
367 };
368
369 static int lvfs_reint_rename(struct super_block *sb, struct reint_record *r_rec)
370 {
371         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
372         char *path = r_rec->name.path_name;
373         char *new_path = r_rec->u.re_name.path_name;
374         struct nameidata nd, new_nd;
375         struct dentry *dparent = NULL;
376         struct dentry *new_dparent = NULL;
377         struct dentry *dentry = NULL;
378         struct dentry *new_dentry = NULL;
379         struct inode *dir = NULL;
380         struct inode *new_dir = NULL;
381         void *handle = NULL;
382         int rc = 0;
383         ENTRY;
384
385         rc = lookup_by_path(path, LOOKUP_PARENT, &nd);
386         if (rc)
387                 RETURN(rc);
388
389         dparent = nd.dentry;
390         dir = dparent->d_inode;
391         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);
392
393         if (IS_ERR(dentry) || !dentry->d_inode || is_bad_inode(dentry->d_inode)) {
394                 path_release(&nd);
395                 RETURN(rc);
396         }
397         rc = lookup_by_path(new_path, LOOKUP_PARENT, &new_nd);
398         if (rc) {
399                 path_release(&nd);
400                 path_release(&new_nd);
401                 RETURN(rc);
402         }
403         new_dparent = new_nd.dentry;
404         new_dir = new_dparent->d_inode;
405         new_dentry = lookup_create(&new_nd, 0);
406
407         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
408                 SMFS_CLEAN_INODE_REC(dir);
409
410         handle = fsfilt->fs_start(dir, FSFILT_OP_RENAME, NULL, 0);
411         if (IS_ERR(handle))
412                 GOTO(cleanup, rc = PTR_ERR(handle));
413
414         rc = vfs_rename(dir, dentry, new_dir, new_dentry);
415         if (rc) {
416                 CERROR("unlink in error path: %d\n", rc);
417                 GOTO(cleanup, 0);
418         } else {
419                 /*restore time attr of dir inode*/
420                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
421
422                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
423                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
424                 if (rc) {
425                         CERROR("error on parent setattr: rc = %d\n", rc);
426                         GOTO(cleanup, rc);
427                 }
428                 rc = fsfilt->fs_setattr(new_dparent, handle, iattr, 0);
429                 if (rc) {
430                         CERROR("error on parent setattr: rc = %d\n", rc);
431                         GOTO(cleanup, rc);
432                 }
433         }
434 cleanup:
435         if (handle)
436                 rc = fsfilt->fs_commit(dir, handle, 0);
437         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
438                 SMFS_SET_INODE_REC(dir);
439         if (dentry)
440                 l_dput(dentry);
441         if (new_dentry)
442                 l_dput(new_dentry);
443         path_release(&nd);
444         path_release(&new_nd);
445         RETURN(0);
446 };
447
448 static int lvfs_reint_setattr(struct super_block *sb,
449                               struct reint_record *r_rec)
450 {
451         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
452         char *path = r_rec->name.path_name;
453         struct nameidata nd;
454         struct dentry *dparent = NULL;
455         struct dentry *dentry = NULL;
456         struct inode *dir = NULL;
457         void *handle = NULL;
458         int rc = 0;
459         ENTRY;
460
461         rc = lookup_by_path(path, LOOKUP_PARENT, &nd);
462         if (rc)
463                 RETURN(rc);
464
465         dparent = nd.dentry;
466         dir = dparent->d_inode;
467         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);
468
469         if (IS_ERR(dentry) || !dentry->d_inode || is_bad_inode(dentry->d_inode)) {
470                 path_release(&nd);
471                 RETURN(rc);
472         }
473         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
474                 SMFS_CLEAN_INODE_REC(dir);
475         handle = fsfilt->fs_start(dir, FSFILT_OP_SETATTR, NULL, 0);
476         if (IS_ERR(handle))
477                 GOTO(cleanup, rc = PTR_ERR(handle));
478         rc = fsfilt->fs_setattr(dentry, handle, &r_rec->u_rec.ur_pattr, 0);
479 cleanup:
480         if (handle)
481                 fsfilt->fs_commit(dir, handle, 0);
482         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
483                 SMFS_SET_INODE_REC(dir);
484         if (dentry)
485                 l_dput(dentry);
486         path_release(&nd);
487         RETURN(0);
488 };
489
490 static int lvfs_reint_close(struct super_block *sb, struct reint_record *r_rec)
491 {
492         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
493         char   *path = r_rec->name.path_name;
494         struct nameidata nd;
495         struct dentry *dparent = NULL;
496         struct dentry *dentry = NULL;
497         struct inode *dir = NULL;
498         void *handle = NULL;
499         struct iattr *iattr = &r_rec->u_rec.ur_iattr;
500         int rc = 0;
501         ENTRY;
502
503         rc = lookup_by_path(path, LOOKUP_PARENT, &nd);
504         if (rc)
505                 RETURN(rc);
506
507         dparent = nd.dentry;
508         dir = dparent->d_inode;
509         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);
510
511         if (IS_ERR(dentry) || !dentry->d_inode || is_bad_inode(dentry->d_inode)) {
512                 path_release(&nd);
513                 RETURN(rc);
514         }
515         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
516                 SMFS_CLEAN_INODE_REC(dir);
517         handle = fsfilt->fs_start(dir, FSFILT_OP_CREATE, NULL, 0);
518         if (IS_ERR(handle))
519                 GOTO(cleanup, rc = PTR_ERR(handle));
520
521         iattr->ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_SIZE;
522         rc = fsfilt->fs_setattr(dentry, handle, iattr, 0);
523         if (rc) {
524                 CERROR("error on parent setattr: rc = %d\n", rc);
525                 GOTO(cleanup, rc);
526         }
527 cleanup:
528         if (handle)
529                 fsfilt->fs_commit(dir, handle, 0);
530         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
531                 SMFS_SET_INODE_REC(dir);
532         if (dentry)
533                 l_dput(dentry);
534         path_release(&nd);
535         RETURN(0);
536 };
537
538 typedef int (*lvfs_reinter)(struct super_block *sb, struct reint_record *);
539 static lvfs_reinter reinters[REINT_MAX + 1] = {
540         [REINT_SETATTR] lvfs_reint_setattr,
541         [REINT_CREATE] lvfs_reint_create,
542         [REINT_LINK] lvfs_reint_link,
543         [REINT_UNLINK] lvfs_reint_unlink,
544         [REINT_RENAME] lvfs_reint_rename,
545         [REINT_CLOSE] lvfs_reint_close,
546 };
547 int lvfs_reint(struct super_block *sb, void *r_rec)
548 {
549         return reinters[((struct reint_record*)r_rec)->u_rec.ur_opcode](sb,
550                         (struct reint_record *)r_rec);
551 };
552
553 EXPORT_SYMBOL(lvfs_reint);