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