Whamcloud - gitweb
landing smfs.
[fs/lustre-release.git] / lustre / lvfs / lvfs_undo.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 static int lvfs_undo_create(struct super_block *sb, 
34                             struct reint_record *r_rec)
35 {
36         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
37         char *path = r_rec->rec_data1;
38         int type = r_rec->u_rec.ur_iattr.ia_mode & S_IFMT;
39         struct nameidata nd;
40         struct dentry *dparent = NULL;
41         struct dentry *dentry = NULL;
42         struct inode *dir = NULL;
43         void *handle = NULL;
44         int rc = 0;
45
46         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
47         if (rc)
48                 RETURN(rc); 
49        
50         dparent = nd.dentry; 
51         dir = dparent->d_inode;
52         
53         down(&dir->i_sem);
54         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);    
55         
56         if (!dentry->d_inode || is_bad_inode(dentry->d_inode)) {
57                 up(&dir->i_sem);
58                 if (dentry)
59                         l_dput(dentry);
60                 path_release(&nd);
61                 RETURN(-ENODEV);
62         } 
63         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
64                 SMFS_CLEAN_INODE_REC(dir);
65         
66         switch(type) {  
67         case S_IFREG:
68         case S_IFLNK:
69         case S_IFCHR:
70         case S_IFBLK:
71         case S_IFIFO:
72         case S_IFSOCK:
73                 handle = fsfilt->fs_start(dir, FSFILT_OP_UNLINK, NULL, 0);
74                 if (IS_ERR(handle))
75                         GOTO(cleanup, rc = PTR_ERR(handle));
76                 rc = vfs_unlink(dir, dentry);
77                 if (rc)
78                         CERROR("unlink in error path: %d\n", rc);
79                 break;
80         case S_IFDIR:
81                 handle = fsfilt->fs_start(dir, FSFILT_OP_RMDIR, NULL, 0);
82                 if (IS_ERR(handle))
83                         GOTO(cleanup, rc = PTR_ERR(handle));
84                 
85                 rc = vfs_rmdir(dir, dentry);
86                 if (rc)
87                         CERROR("rmdir in error path: %d\n", rc);
88                 break;
89         default:
90                 CERROR("Error type %d in create\n", type);
91                 rc = -EINVAL;
92                 break;
93         }  
94        
95         if (rc) {
96                 CERROR("Error for undo node %s\n", path);
97                 GOTO(cleanup, 0); 
98         } else {
99                 /*restore time attr of dir inode*/
100                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
101                 
102                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
103                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
104                 if (rc) {
105                         CERROR("error on parent setattr: rc = %d\n", rc);
106                         GOTO(cleanup, rc);
107                 }
108         }
109 cleanup:
110         if (handle) 
111                 rc = fsfilt->fs_commit(dparent->d_inode, handle, 0);
112         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
113                 SMFS_SET_INODE_REC(dir);
114         if (dentry)
115                 l_dput(dentry);
116         up(&dir->i_sem);
117         path_release(&nd);
118         RETURN(0);
119 };
120
121 static int lvfs_undo_link(struct super_block *sb, 
122                           struct reint_record *r_rec)
123 {
124         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
125         char   *new_path = r_rec->rec_data2;
126         struct nameidata nd;
127         struct dentry *dparent = NULL;
128         struct dentry *dentry = NULL;
129         struct inode *dir = NULL;
130         void *handle = NULL;
131         int rc = 0;
132
133         rc = lookup_by_path(new_path, LOOKUP_PARENT, &nd); 
134         if (rc)
135                 RETURN(rc); 
136        
137         dparent = nd.dentry; 
138         dir = dparent->d_inode;
139         
140         down(&dir->i_sem);
141         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);    
142         
143         if (!dentry->d_inode || is_bad_inode(dentry->d_inode)) {
144                 up(&dir->i_sem);
145                 path_release(&nd);
146                 RETURN(-ENODEV);
147         } 
148         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
149                 SMFS_CLEAN_INODE_REC(dir);
150         
151         handle = fsfilt->fs_start(dir, FSFILT_OP_UNLINK, NULL, 0);
152         if (IS_ERR(handle))
153                 GOTO(cleanup, rc = PTR_ERR(handle));
154         rc = vfs_unlink(dir, dentry);
155         if (rc)
156                 CERROR("unlink in error path: %d\n", rc);
157
158         if (rc) {
159                 CERROR("Error for undo node %s\n", new_path);
160                 GOTO(cleanup, 0); 
161         } else {
162                 /*restore time attr of dir inode*/
163                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
164                 
165                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
166                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
167                 if (rc) {
168                         CERROR("error on parent setattr: rc = %d\n", rc);
169                         GOTO(cleanup, rc);
170                 }
171         }
172 cleanup:
173         if (handle) 
174                 rc = fsfilt->fs_commit(dir, handle, 0);
175         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
176                 SMFS_SET_INODE_REC(dir);
177         if (dentry)
178                 l_dput(dentry);
179         up(&dir->i_sem);
180         path_release(&nd);
181         RETURN(0);
182 }       
183
184 static int lvfs_undo_unlink(struct super_block *sb, 
185                              struct reint_record *r_rec)
186 {
187         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
188         char   *path = r_rec->rec_data1;
189         struct nameidata nd;
190         struct dentry *dparent;
191         struct dentry *dentry = NULL;
192         struct nameidata del_nd;
193         struct dentry *del_dparent = NULL;
194         struct dentry *del_dentry = NULL;
195         void   *handle = NULL;
196         struct inode *dir = NULL;
197         int    rc = 0;
198         
199         /*get parent dentry*/   
200         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
201         if (rc)
202                 RETURN(rc); 
203        
204         dparent = nd.dentry;
205         dir = dparent->d_inode;
206         
207         dentry = lookup_create(&nd, 0);
208         
209         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
210                 SMFS_CLEAN_INODE_REC(dir);
211         if (SMFS_DO_DEC_LINK(r_rec->u_rec.ur_flags)) {
212                 ino_t ino = *((ino_t *)r_rec->rec_data2);
213                 struct inode* inode = iget(dir->i_sb, ino);
214                 if (!inode) 
215                         GOTO(cleanup1, rc = -EINVAL);        
216                 handle = fsfilt->fs_start(dir, FSFILT_OP_LINK, NULL, 0);
217                 if (IS_ERR(handle))
218                         GOTO(cleanup1, rc = PTR_ERR(handle));
219                 
220                 del_dentry = pre_smfs_dentry(NULL, inode, dentry);
221                 rc = vfs_link(del_dentry, dir, dentry); 
222 cleanup1:
223                 post_smfs_dentry(del_dentry);
224                 iput(inode);
225         } else {
226                 char   *del_path = r_rec->rec_data2;
227                              
228                 rc = lookup_by_path(del_path, LOOKUP_PARENT, &del_nd);
229                 if (rc) 
230                         GOTO(cleanup, rc = -ENODEV);
231                 del_dparent = del_nd.dentry;
232                 del_dentry = lookup_one_len(del_nd.last.name, del_dparent, 
233                                     del_nd.last.len);    
234
235                 if (! del_dentry || !del_dentry->d_inode 
236                     || is_bad_inode(del_dentry->d_inode)) 
237                         GOTO(cleanup2, rc = -ENODEV);
238
239                 handle = fsfilt->fs_start(dir, FSFILT_OP_RENAME, NULL, 0);
240                 if (IS_ERR(handle))
241                         GOTO(cleanup2, rc = PTR_ERR(handle));
242
243                 lock_kernel();
244                 /*move the del dentry back to the original palace*/
245                 rc = vfs_rename(del_dparent->d_inode, del_dentry, dir, dentry);
246                 unlock_kernel();
247                 if (!rc && S_ISDIR(del_dentry->d_inode->i_mode))
248                         del_dentry->d_inode->i_flags &=~S_DEAD;
249 cleanup2:
250                 if (del_dentry)
251                         l_dput(del_dentry);
252                 path_release(&del_nd);
253         }
254         if (!rc) {
255                /*restore time attr of dir inode*/
256                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
257                 
258                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
259                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
260                 if (rc) {
261                         CERROR("error on parent setattr: rc = %d\n", rc);
262                         GOTO(cleanup, rc);
263                 }
264         } 
265 cleanup:
266         if (handle) 
267                 fsfilt->fs_commit(dir, handle, 0);
268         if (dentry);
269                 l_dput(dentry);
270         path_release(&nd);
271         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
272                 SMFS_SET_INODE_REC(dir);
273         RETURN(rc);
274 }
275
276 static int lvfs_undo_rename(struct super_block *sb, 
277                              struct reint_record *r_rec)
278 {
279         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
280         char   *path = r_rec->rec_data1;
281         char   *new_path = r_rec->rec_data2;
282         struct nameidata nd;
283         struct nameidata new_nd;
284         struct dentry *dparent;
285         struct dentry *new_dparent;
286         struct dentry *dentry = NULL;
287         struct dentry *new_dentry = NULL;
288         void   *handle = NULL;
289         struct inode *dir = NULL;
290         struct inode *new_dir = NULL;
291         int    rc = 0;
292         
293         /*get parent dentry*/   
294         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
295         if (rc)
296                 RETURN(rc); 
297        
298         dparent = nd.dentry;
299         dir = dparent->d_inode;
300         dentry = lookup_create(&nd, 0);
301         
302         rc = lookup_by_path(new_path, LOOKUP_PARENT, &new_nd);
303         if (rc) {
304                 path_release(&nd); 
305                 RETURN(rc);
306         }
307         new_dparent = new_nd.dentry;
308         new_dir = new_dparent->d_inode;
309         new_dentry = lookup_one_len(new_nd.last.name, new_dparent, 
310                                     new_nd.last.len);    
311         
312         if (! new_dentry || !new_dentry->d_inode 
313             || is_bad_inode(new_dentry->d_inode)) {
314                 GOTO(cleanup, rc = -ENODEV);
315         }       
316         
317         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
318                 SMFS_CLEAN_INODE_REC(new_dir);
319          
320         handle = fsfilt->fs_start(new_dir, FSFILT_OP_RENAME, NULL, 0);
321         if (IS_ERR(handle))
322                 GOTO(cleanup, rc = PTR_ERR(handle));
323
324         lock_kernel();
325         /*move the del dentry back to the original palace*/
326         rc = vfs_rename(new_dir, new_dentry, dir, dentry);
327         unlock_kernel();
328         if (rc) {
329                 CERROR("Error for undo node %s\n", new_path);
330                 GOTO(cleanup, 0); 
331         } else {
332                 /*restore time attr of dir inode*/
333                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
334                 
335                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
336                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
337                 if (rc) {
338                         CERROR("error on parent setattr: rc = %d\n", rc);
339                         GOTO(cleanup, rc);
340                 }
341         }
342 cleanup:
343         if (handle) 
344                 rc = fsfilt->fs_commit(new_dir, handle, 0);
345         if (dentry);
346                 l_dput(dentry);
347         if (new_dentry)
348                 l_dput(new_dentry);
349         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
350                 SMFS_SET_INODE_REC(new_dir);
351         path_release(&nd);
352         path_release(&new_nd);
353         RETURN(rc);
354 };
355
356 static int lvfs_undo_setattr(struct super_block *sb, 
357                              struct reint_record *r_rec)
358 {
359         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
360         char *path = r_rec->rec_data1;
361         struct nameidata nd;
362         struct dentry *dparent = NULL;
363         struct dentry *dentry = NULL;
364         struct inode *dir = NULL;
365         void *handle = NULL;
366         int rc = 0;
367
368         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
369         if (rc)
370                 RETURN(rc); 
371         
372         dparent = nd.dentry;
373         dir = dparent->d_inode;
374         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);
375  
376         if (!dentry || !dentry->d_inode 
377             || is_bad_inode(dentry->d_inode)) {
378                 path_release(&nd);
379                 RETURN(rc);
380         }       
381         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags)) 
382                 SMFS_CLEAN_INODE_REC(dir);
383         handle = fsfilt->fs_start(dir, FSFILT_OP_SETATTR, NULL, 0);
384         if (IS_ERR(handle))
385                 GOTO(cleanup, rc = PTR_ERR(handle));
386         
387         /*FIXME later, did not set parent attr*/
388         r_rec->u_rec.ur_iattr.ia_valid = r_rec->u_rec.ur_pattr.ia_valid;
389         rc = fsfilt->fs_setattr(dentry, handle, &r_rec->u_rec.ur_iattr, 0);
390 cleanup:  
391         if (handle)
392                 fsfilt->fs_commit(dir, handle, 0); 
393         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
394                 SMFS_SET_INODE_REC(dir);
395         if (dentry)
396                 l_dput(dentry);
397         path_release(&nd);
398         RETURN(0);
399        
400         RETURN(0);
401 }; 
402
403
404 typedef int (*lvfs_undoer)(struct super_block *sb, struct reint_record *);
405
406 static lvfs_undoer undoers[REINT_MAX + 1] = {
407         [REINT_SETATTR] lvfs_undo_setattr,
408         [REINT_CREATE] lvfs_undo_create,
409         [REINT_LINK] lvfs_undo_link,
410         [REINT_UNLINK] lvfs_undo_unlink,
411         [REINT_RENAME] lvfs_undo_rename,
412 };
413
414 int lvfs_undo(struct super_block *sb, 
415               void *r_rec)
416 {
417         return  undoers[((struct reint_record*)r_rec)->u_rec.ur_opcode](sb, 
418                          (struct reint_record *)r_rec);     
419 };
420
421 EXPORT_SYMBOL(lvfs_undo);