Whamcloud - gitweb
landing b_cmobd_merge on HEAD
[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->name.path_name;
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->u.re_name.path_name;
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                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
163                 
164                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
165                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
166                 if (rc) {
167                         CERROR("error on parent setattr: rc = %d\n", rc);
168                         GOTO(cleanup, rc);
169                 }
170         }
171 cleanup:
172         if (handle) 
173                 rc = fsfilt->fs_commit(dir, handle, 0);
174         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
175                 SMFS_SET_INODE_REC(dir);
176         if (dentry)
177                 l_dput(dentry);
178         up(&dir->i_sem);
179         path_release(&nd);
180         RETURN(0);
181 }       
182
183 static int lvfs_undo_unlink(struct super_block *sb, 
184                              struct reint_record *r_rec)
185 {
186         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
187         char   *path = r_rec->name.path_name;
188         struct nameidata nd;
189         struct dentry *dparent;
190         struct dentry *dentry = NULL;
191         struct nameidata del_nd;
192         struct dentry *del_dparent = NULL;
193         struct dentry *del_dentry = NULL;
194         void   *handle = NULL;
195         struct inode *dir = NULL;
196         int    rc = 0;
197         
198         /*get parent dentry*/   
199         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
200         if (rc)
201                 RETURN(rc); 
202        
203         dparent = nd.dentry;
204         dir = dparent->d_inode;
205         
206         dentry = lookup_create(&nd, 0);
207         
208         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
209                 SMFS_CLEAN_INODE_REC(dir);
210         if (SMFS_DO_DEC_LINK(r_rec->u_rec.ur_flags)) {
211                 ino_t ino = *((ino_t *)r_rec->u.re_name.path_name);
212                 struct inode* inode = iget(dir->i_sb, ino);
213                 if (!inode) 
214                         GOTO(cleanup1, rc = -EINVAL);        
215                 handle = fsfilt->fs_start(dir, FSFILT_OP_LINK, NULL, 0);
216                 if (IS_ERR(handle))
217                         GOTO(cleanup1, rc = PTR_ERR(handle));
218                 
219                 del_dentry = pre_smfs_dentry(NULL, inode, dentry);
220                 rc = vfs_link(del_dentry, dir, dentry); 
221 cleanup1:
222                 post_smfs_dentry(del_dentry);
223                 iput(inode);
224         } else {
225                 char   *del_path = r_rec->u.re_name.path_name;
226                              
227                 rc = lookup_by_path(del_path, LOOKUP_PARENT, &del_nd);
228                 if (rc) 
229                         GOTO(cleanup, rc = -ENODEV);
230                 del_dparent = del_nd.dentry;
231                 del_dentry = lookup_one_len(del_nd.last.name, del_dparent, 
232                                     del_nd.last.len);    
233
234                 if (! del_dentry || !del_dentry->d_inode 
235                     || is_bad_inode(del_dentry->d_inode)) 
236                         GOTO(cleanup2, rc = -ENODEV);
237
238                 handle = fsfilt->fs_start(dir, FSFILT_OP_RENAME, NULL, 0);
239                 if (IS_ERR(handle))
240                         GOTO(cleanup2, rc = PTR_ERR(handle));
241
242                 lock_kernel();
243                 /*move the del dentry back to the original palace*/
244                 rc = vfs_rename(del_dparent->d_inode, del_dentry, dir, dentry);
245                 unlock_kernel();
246                 if (!rc && S_ISDIR(del_dentry->d_inode->i_mode))
247                         del_dentry->d_inode->i_flags &=~S_DEAD;
248 cleanup2:
249                 if (del_dentry)
250                         l_dput(del_dentry);
251                 path_release(&del_nd);
252         }
253
254         if (!rc) {
255                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
256                 
257                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
258                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
259                 if (rc) {
260                         CERROR("error on parent setattr: rc = %d\n", rc);
261                         GOTO(cleanup, rc);
262                 }
263         } 
264 cleanup:
265         if (handle) 
266                 fsfilt->fs_commit(dir, handle, 0);
267         if (dentry);
268                 l_dput(dentry);
269         path_release(&nd);
270         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
271                 SMFS_SET_INODE_REC(dir);
272         RETURN(rc);
273 }
274
275 static int lvfs_undo_rename(struct super_block *sb, 
276                              struct reint_record *r_rec)
277 {
278         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
279         char   *path = r_rec->name.path_name;
280         char   *new_path = r_rec->u.re_name.path_name;
281         struct nameidata nd;
282         struct nameidata new_nd;
283         struct dentry *dparent;
284         struct dentry *new_dparent;
285         struct dentry *dentry = NULL;
286         struct dentry *new_dentry = NULL;
287         void   *handle = NULL;
288         struct inode *dir = NULL;
289         struct inode *new_dir = NULL;
290         int    rc = 0;
291         
292         /*get parent dentry*/   
293         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
294         if (rc)
295                 RETURN(rc); 
296        
297         dparent = nd.dentry;
298         dir = dparent->d_inode;
299         dentry = lookup_create(&nd, 0);
300         
301         rc = lookup_by_path(new_path, LOOKUP_PARENT, &new_nd);
302         if (rc) {
303                 path_release(&nd); 
304                 RETURN(rc);
305         }
306         new_dparent = new_nd.dentry;
307         new_dir = new_dparent->d_inode;
308         new_dentry = lookup_one_len(new_nd.last.name, new_dparent, 
309                                     new_nd.last.len);    
310         
311         if (! new_dentry || !new_dentry->d_inode 
312             || is_bad_inode(new_dentry->d_inode)) {
313                 GOTO(cleanup, rc = -ENODEV);
314         }       
315         
316         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
317                 SMFS_CLEAN_INODE_REC(new_dir);
318          
319         handle = fsfilt->fs_start(new_dir, FSFILT_OP_RENAME, NULL, 0);
320         if (IS_ERR(handle))
321                 GOTO(cleanup, rc = PTR_ERR(handle));
322
323         lock_kernel();
324         /*move the del dentry back to the original palace*/
325         rc = vfs_rename(new_dir, new_dentry, dir, dentry);
326         unlock_kernel();
327         if (rc) {
328                 CERROR("Error for undo node %s\n", new_path);
329                 GOTO(cleanup, 0); 
330         } else {
331                 struct iattr *iattr = &r_rec->u_rec.ur_pattr;
332                 
333                 iattr->ia_valid = ATTR_MTIME | ATTR_CTIME;
334                 rc = fsfilt->fs_setattr(dparent, handle, iattr, 0);
335                 if (rc) {
336                         CERROR("error on parent setattr: rc = %d\n", rc);
337                         GOTO(cleanup, rc);
338                 }
339         }
340 cleanup:
341         if (handle) 
342                 rc = fsfilt->fs_commit(new_dir, handle, 0);
343         if (dentry);
344                 l_dput(dentry);
345         if (new_dentry)
346                 l_dput(new_dentry);
347         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
348                 SMFS_SET_INODE_REC(new_dir);
349         path_release(&nd);
350         path_release(&new_nd);
351         RETURN(rc);
352 };
353
354 static int lvfs_undo_setattr(struct super_block *sb, 
355                              struct reint_record *r_rec)
356 {
357         struct fsfilt_operations *fsfilt = S2SMI(sb)->sm_fsfilt;
358         char *path = r_rec->name.path_name;
359         struct nameidata nd;
360         struct dentry *dparent = NULL;
361         struct dentry *dentry = NULL;
362         struct inode *dir = NULL;
363         void *handle = NULL;
364         int rc = 0;
365
366         rc = lookup_by_path(path, LOOKUP_PARENT, &nd); 
367         if (rc)
368                 RETURN(rc); 
369         
370         dparent = nd.dentry;
371         dir = dparent->d_inode;
372         dentry = lookup_one_len(nd.last.name, dparent, nd.last.len);
373  
374         if (!dentry || !dentry->d_inode 
375             || is_bad_inode(dentry->d_inode)) {
376                 path_release(&nd);
377                 RETURN(rc);
378         }       
379         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags)) 
380                 SMFS_CLEAN_INODE_REC(dir);
381         handle = fsfilt->fs_start(dir, FSFILT_OP_SETATTR, NULL, 0);
382         if (IS_ERR(handle))
383                 GOTO(cleanup, rc = PTR_ERR(handle));
384         
385         /* FIXME later, did not set parent attr. */
386         r_rec->u_rec.ur_iattr.ia_valid = r_rec->u_rec.ur_pattr.ia_valid;
387         rc = fsfilt->fs_setattr(dentry, handle, &r_rec->u_rec.ur_iattr, 0);
388 cleanup:  
389         if (handle)
390                 fsfilt->fs_commit(dir, handle, 0); 
391         if (!SMFS_DO_WRITE_KML(r_rec->u_rec.ur_flags))
392                 SMFS_SET_INODE_REC(dir);
393         if (dentry)
394                 l_dput(dentry);
395         path_release(&nd);
396         RETURN(0);
397        
398         RETURN(0);
399 }; 
400
401
402 typedef int (*lvfs_undoer)(struct super_block *sb, struct reint_record *);
403
404 static lvfs_undoer undoers[REINT_MAX + 1] = {
405         [REINT_SETATTR] lvfs_undo_setattr,
406         [REINT_CREATE] lvfs_undo_create,
407         [REINT_LINK] lvfs_undo_link,
408         [REINT_UNLINK] lvfs_undo_unlink,
409         [REINT_RENAME] lvfs_undo_rename,
410 };
411
412 int lvfs_undo(struct super_block *sb, 
413               void *r_rec)
414 {
415         return  undoers[((struct reint_record*)r_rec)->u_rec.ur_opcode](sb, 
416                          (struct reint_record *)r_rec);     
417 };
418
419 EXPORT_SYMBOL(lvfs_undo);