Whamcloud - gitweb
1)reorganize the smfs hook ops to make smfs walk a list of hooks ops in hook macro
[fs/lustre-release.git] / lustre / smfs / journal.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/smfs/journal.c
5  *  Lustre filesystem abstraction routines
6  *
7  *  Copyright (C) 2004 Cluster File Systems, Inc.
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 #define DEBUG_SUBSYSTEM S_SM
25
26 #include <linux/kmod.h>
27 #include <linux/init.h>
28 #include <linux/fs.h>
29 #include <linux/slab.h>
30 #include <linux/string.h>
31 #include <asm/segment.h>
32 #include <asm/uaccess.h>
33 #include <linux/obd_class.h>
34 #include <linux/obd_support.h>
35 #include <linux/lustre_lib.h>
36 #include <linux/lustre_idl.h>
37 #include <linux/lustre_fsfilt.h>
38 #include <linux/lustre_smfs.h>
39 #include <linux/lvfs.h>
40 #include "smfs_internal.h"
41
42 #define KML_BUF_REC_INIT(buffer, pbuf, len)     \
43 do {                                            \
44         pbuf = buffer + sizeof(int);            \
45         len -= sizeof(int);                     \
46 } while (0)
47         
48 #define KML_BUF_REC_END(buffer, length, pbuf)   \
49 do {                                            \
50         int len = length;                       \
51         memcpy(buffer, &len, sizeof(len));      \
52         length += sizeof(int);                  \
53         pbuf = buffer + length;                 \
54 } while (0)
55
56 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
57 {
58         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
59
60         CDEBUG(D_INFO, "trans start %p\n", fsfilt->fs_start);
61
62         SMFS_TRANS_OP(inode, op);
63         
64         /* There are some problem here. fs_start in fsfilt is used by lustre
65          * the journal blocks of write rec are not counted in FIXME later */
66         if (fsfilt->fs_start)
67                 return fsfilt->fs_start(inode, op, desc_private, 0);
68         return NULL;
69 }
70
71 void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
72 {
73         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
74
75         if (!handle)
76                 return;
77
78         CDEBUG(D_INFO, "trans commit %p\n", fsfilt->fs_commit);
79
80         if (fsfilt->fs_commit)
81                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
82 }
83
84 /*smfs_path is gotten from intermezzo*/
85 static char* smfs_path(struct dentry *dentry, struct dentry *root, char *buffer,
86                        int buflen)
87 {
88         char * end = buffer + buflen;
89         char * name = buffer;
90         char * buf_end = buffer + buflen;
91         char * retval;
92
93         *--end = '\0';
94         buflen--;
95         /* Get '/' right */
96         retval = end-1;
97         *retval = '/';
98
99         for (;;) {
100                 struct dentry * parent;
101                 int namelen;
102
103                 if (dentry == root)
104                         break;
105                 parent = dentry->d_parent;
106                 if (dentry == parent)
107                         break;
108                 namelen = dentry->d_name.len;
109                 buflen -= namelen + 1;
110                 if (buflen < 0)
111                         break;
112                 end -= namelen;
113                 memcpy(end, dentry->d_name.name, namelen);
114                 *--end = '/';
115                 retval = end;
116                 dentry = parent;
117         }
118         
119         while (end != buf_end) 
120                 *name++ = *end++;
121         *name = '\0'; 
122         return retval;
123 }
124
125 static int smfs_log_path(struct super_block *sb, 
126                          struct dentry *dentry, 
127                          char   *buffer,
128                          int    buffer_len)
129 {
130         struct dentry *root=sb->s_root;
131         char *p_name = buffer + sizeof(int);
132         char *name = NULL;
133         int namelen = 0;
134         if (dentry) {
135                 name = smfs_path(dentry, root, p_name, buffer_len - sizeof(int));
136                 namelen = cpu_to_le32(strlen(p_name));
137                 memcpy(buffer, &namelen, sizeof(int));        
138         }
139         namelen += sizeof(int);
140         RETURN(namelen);
141 }
142
143 static inline int log_it(char *buffer, void *data, int length)
144 {
145         memcpy(buffer, &length, sizeof(int));
146         memcpy(buffer + sizeof(int), data, length);
147         return (sizeof(int) + length);                 
148 }
149
150 static int smfs_pack_rec (char *buffer, struct dentry *dentry, 
151                           struct inode *dir, void *data1, 
152                           void *data2, int op)
153
154         smfs_pack_rec_func pack_func;        
155         int rc;
156
157         pack_func = smfs_get_rec_pack_type(dir->i_sb);
158         if (!pack_func) {
159                 return (0);
160         }
161         rc = pack_func(buffer, dentry, dir, data1, data2, op);
162         return rc;
163 }
164
165 int smfs_post_rec_create(struct inode *dir, struct dentry *dentry,
166                          void   *data1, void   *data2)
167 {
168         struct smfs_super_info *sinfo;
169         char   *buffer = NULL, *pbuf;
170         int rc = 0, length = 0, buf_len = 0;
171         
172         sinfo = S2SMI(dentry->d_inode->i_sb);
173         if (!sinfo)
174                 RETURN(-EINVAL);
175         
176         OBD_ALLOC(buffer, PAGE_SIZE);
177         if (!buffer)
178                 GOTO(exit, rc = -ENOMEM);        
179
180         buf_len = PAGE_SIZE;
181         KML_BUF_REC_INIT(buffer, pbuf, buf_len);
182         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
183         if (rc < 0)
184                 GOTO(exit, rc);
185         length = rc;
186         KML_BUF_REC_END(buffer, length, pbuf);   
187        
188         rc = smfs_pack_rec(pbuf, dentry, dir, 
189                            data1, data2, REINT_CREATE);
190         if (rc <= 0)
191                 GOTO(exit, rc);
192         else
193                 length += rc;
194         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
195 exit:
196         if (buffer)
197                 OBD_FREE(buffer, PAGE_SIZE);        
198         
199         RETURN(rc);
200 }
201
202 static int smfs_post_rec_link(struct inode *dir, 
203                               struct dentry *dentry,
204                                void   *data1,
205                               void   *data2)
206 {
207         struct smfs_super_info *sinfo;
208         struct dentry *old_dentry = (struct dentry *)data1;
209         char *buffer = NULL, *pbuf = NULL;
210         int rc = 0, length = 0, buf_len = 0;
211         
212         sinfo = S2SMI(dir->i_sb);
213         if (!sinfo)
214                 RETURN(-EINVAL);
215         OBD_ALLOC(buffer, PAGE_SIZE);
216         if (!buffer)
217                 GOTO(exit, rc = -ENOMEM);
218         
219         buf_len = PAGE_SIZE;
220         KML_BUF_REC_INIT(buffer, pbuf, buf_len);
221         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
222         if (rc < 0)
223                 GOTO(exit, rc);
224         
225         length = rc;
226         KML_BUF_REC_END(buffer, length, pbuf);  
227         
228         rc = smfs_pack_rec(pbuf, dentry, dir, dentry->d_parent, 
229                            old_dentry->d_parent, REINT_LINK);
230         if (rc <= 0)
231                 GOTO(exit, rc);
232         else
233                 length += rc;
234         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
235 exit:
236         if (buffer)
237                 OBD_FREE(buffer, PAGE_SIZE);        
238         
239         RETURN(rc);
240 }
241
242 static int smfs_post_rec_unlink(struct inode *dir, struct dentry *dentry,
243                                 void *data1, void *data2)
244 {
245         struct smfs_super_info *sinfo;
246         int mode = *((int*)data1);
247         char   *buffer = NULL, *pbuf = NULL;
248         int  length = 0, rc = 0, buf_len = 0;
249          
250         sinfo = S2SMI(dentry->d_inode->i_sb);
251         if (!sinfo)
252                 RETURN(-EINVAL);
253         
254         OBD_ALLOC(buffer, PAGE_SIZE);
255         if (!buffer)
256                 GOTO(exit, rc = -ENOMEM);        
257       
258         buf_len = PAGE_SIZE;
259         KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
260         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
261         if (rc < 0)
262                 GOTO(exit, rc);
263
264         length = rc;
265         KML_BUF_REC_END(buffer, length, pbuf);
266         rc = smfs_pack_rec(pbuf, dentry, dir, 
267                            &mode, NULL, REINT_UNLINK);
268         if (rc <= 0)
269                 GOTO(exit, rc);
270         else
271                 length += rc;         
272         
273         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
274 exit:
275         if (buffer)
276                 OBD_FREE(buffer, PAGE_SIZE);        
277         
278         RETURN(rc);
279 }
280
281 static int smfs_post_rec_rename(struct inode *dir, 
282                                  struct dentry *dentry,
283                                  void   *data1,
284                                 void   *data2)
285 {
286         struct smfs_super_info *sinfo;
287         struct inode *new_dir = (struct inode *)data1;
288         struct dentry *new_dentry = (struct dentry *)data2;
289         char *buffer = NULL, *pbuf = NULL;
290         int rc = 0, length = 0, buf_len = 0;
291         
292         sinfo = S2SMI(dir->i_sb);
293         if (!sinfo)
294                 RETURN(-EINVAL);
295
296         OBD_ALLOC(buffer, PAGE_SIZE);
297         if (!buffer)
298                 GOTO(exit, rc = -ENOMEM);
299         
300         buf_len = PAGE_SIZE;
301         KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
302         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
303         if (rc < 0)
304                 GOTO(exit, rc);
305
306         pbuf += rc; 
307         length += rc;
308         buf_len -= rc;         
309         /*record new_dentry path*/        
310         rc = smfs_log_path(dir->i_sb, new_dentry, pbuf, buf_len);
311         if (rc < 0)
312                 GOTO(exit, rc);
313
314         length += rc;
315         KML_BUF_REC_END(buffer, length, pbuf);
316                
317         rc = smfs_pack_rec(pbuf, dentry, dir, 
318                            new_dir, new_dentry, REINT_RENAME);
319         if (rc <= 0) 
320                 GOTO(exit, rc);
321         length += rc;
322         
323         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
324 exit:
325         if (buffer)
326                 OBD_FREE(buffer, PAGE_SIZE);
327         RETURN(rc);
328 }
329
330 static int smfs_insert_extents_ea(struct inode *inode, size_t from, loff_t num)
331 {
332         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
333         int rc = 0;
334         
335         if (SMFS_INODE_OVER_WRITE(inode))
336                 RETURN(rc);
337         
338         rc = fsfilt->fs_insert_extents_ea(inode, OFF2BLKS(from, inode), 
339                                           SIZE2BLKS(num, inode));        
340         RETURN(rc);
341 }
342
343 static int smfs_remove_extents_ea(struct inode *inode, size_t from, loff_t num)
344 {
345         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
346         int rc = 0;
347         
348         rc = fsfilt->fs_remove_extents_ea(inode, OFF2BLKS(from, inode), 
349                                           SIZE2BLKS(num, inode));        
350         
351         RETURN(rc);
352 }
353
354 static int smfs_remove_all_extents_ea(struct inode *inode)
355 {
356         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
357         int rc = 0;
358         
359         rc = fsfilt->fs_remove_extents_ea(inode, 0, 0xffffffff);        
360         RETURN(rc);
361 }
362 static int  smfs_init_extents_ea(struct inode *inode)
363 {
364         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
365         int rc = 0;
366         
367         rc = fsfilt->fs_init_extents_ea(inode);        
368         
369         RETURN(rc);
370 }
371 static int smfs_set_dirty_flags(struct inode *inode, int flags)
372 {
373         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
374         void   *handle;
375         int    rc = 0;
376
377         if (SMFS_INODE_OVER_WRITE(inode))
378                 RETURN(rc);
379         /*FIXME later, the blocks needed in journal here will be recalculated*/
380          handle = smfs_trans_start(inode, FSFILT_OP_SETATTR, NULL);
381         if (IS_ERR(handle)) {
382                 CERROR("smfs_set_dirty_flag:no space for transaction\n");
383                 RETURN(-ENOSPC);
384         }
385         if ((!SMFS_INODE_DIRTY_WRITE(inode) && (!SMFS_INODE_OVER_WRITE(inode))) || 
386              ((flags == SMFS_OVER_WRITE) && (SMFS_INODE_DIRTY_WRITE(inode)))) {        
387                 rc = fsfilt->fs_set_xattr(inode, handle, REINT_EXTENTS_FLAGS,
388                                             &flags, sizeof(int));
389                 if (rc)
390                         GOTO(out, rc);
391         }
392         if (flags == SMFS_OVER_WRITE)
393                 SMFS_SET_INODE_OVER_WRITE(inode);
394         else
395                 SMFS_SET_INODE_DIRTY_WRITE(inode);
396 out:
397         smfs_trans_commit(inode, handle, 0);
398         RETURN(rc);
399 }
400
401 int smfs_post_rec_setattr(struct inode *inode, struct dentry *dentry,
402                           void  *data1, void  *data2)
403 {        
404         struct smfs_super_info *sinfo;
405         struct iattr *attr = (struct iattr *)data1;
406         char   *buffer = NULL, *pbuf;
407         int rc = 0, length = 0, buf_len = 0;
408
409         sinfo = S2SMI(inode->i_sb);
410         if (!sinfo)
411                 RETURN(-EINVAL);
412         
413         OBD_ALLOC(buffer, PAGE_SIZE);
414         if (!buffer)
415                 GOTO(exit, rc = -ENOMEM);        
416
417         buf_len = PAGE_SIZE;
418         KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
419         rc = smfs_log_path(inode->i_sb, dentry, pbuf, buf_len);
420         if (rc < 0)
421                 GOTO(exit, rc);
422         
423         length = rc;
424         KML_BUF_REC_END(buffer, length, pbuf);
425         
426         rc = smfs_pack_rec(pbuf, dentry, inode, 
427                            data1, data2, REINT_SETATTR);
428         if (rc <= 0) 
429                 GOTO(exit, rc);
430         else
431                 length += rc;
432
433         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
434         if (!rc) {
435                 if (attr && attr->ia_valid & ATTR_SIZE) {
436                         smfs_remove_extents_ea(inode, attr->ia_size,
437                                                0xffffffff);                                
438                         if (attr->ia_size == 0)
439                                 smfs_set_dirty_flags(inode, SMFS_OVER_WRITE);
440                         else
441                                 smfs_set_dirty_flags(inode, SMFS_DIRTY_WRITE);
442                 }
443         }
444 exit:
445         if (buffer)
446                 OBD_FREE(buffer, PAGE_SIZE);        
447         RETURN(rc);
448 }
449  
450 static int all_blocks_present_ea(struct inode *inode)
451 {
452         int rc = 0;
453         
454         RETURN(rc);        
455 }
456 int smfs_post_rec_write(struct inode *dir, struct dentry *dentry,
457                         void   *data1, void *data2)
458 {
459         struct smfs_super_info *sinfo;
460         char   *buffer = NULL, *pbuf;
461         int rc = 0, length = 0, buf_len = 0;
462         
463         if (!SMFS_INODE_OVER_WRITE(dentry->d_inode) && 
464             !SMFS_INODE_DIRTY_WRITE(dentry->d_inode)) {
465                 sinfo = S2SMI(dentry->d_inode->i_sb);
466                 if (!sinfo)
467                         RETURN(-EINVAL);
468                 
469                 OBD_ALLOC(buffer, PAGE_SIZE);
470                 if (!buffer)
471                         GOTO(exit, rc = -ENOMEM);        
472                 
473                 buf_len = PAGE_SIZE;
474                 KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
475                 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
476                 
477                 if (rc < 0)
478                         GOTO(exit, rc);
479                 pbuf += rc;
480                 memcpy(buffer, &rc, sizeof(int));        
481                 length = rc + sizeof(int);
482                         
483                 rc = smfs_pack_rec(pbuf, dentry, dir, 
484                                    data1, data2, REINT_WRITE);
485                 if (rc <= 0) 
486                         GOTO(exit, rc);
487                 else
488                         length += rc;
489  
490                 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
491                 if (rc)
492                         GOTO(exit, rc);
493                 rc = smfs_init_extents_ea(dentry->d_inode);
494                 if (rc)
495                         GOTO(exit, rc);
496         } 
497         if (dentry->d_inode->i_size == 0) {
498                 smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);        
499         } else {
500                 /*insert extent EA*/
501                 loff_t off = *((loff_t*)data1);        
502                 size_t count = *((size_t*)data2);
503                 
504                 rc = smfs_insert_extents_ea(dentry->d_inode, off, count);        
505                 if (rc < 0)  
506                         GOTO(exit, rc);        
507                 if (all_blocks_present_ea(dentry->d_inode)){
508                         smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);        
509                         smfs_remove_all_extents_ea(dentry->d_inode);
510                 } else {
511                         smfs_set_dirty_flags(dentry->d_inode, SMFS_DIRTY_WRITE);        
512                 }
513         }
514 exit:
515         if (buffer)
516                 OBD_FREE(buffer, PAGE_SIZE);
517         RETURN(rc);
518 }
519
520 typedef int (*post_kml_rec)(struct inode *dir, struct dentry *dentry,
521                            void *data1, void *data2);
522
523 static post_kml_rec smfs_kml_post[HOOK_MAX + 1] = {
524         [HOOK_CREATE]  smfs_post_rec_create,
525         [HOOK_LOOKUP]  NULL,
526         [HOOK_LINK]    smfs_post_rec_link,
527         [HOOK_UNLINK]  smfs_post_rec_unlink,
528         [HOOK_SYMLINK] smfs_post_rec_create,
529         [HOOK_MKDIR]   smfs_post_rec_create,
530         [HOOK_RMDIR]   smfs_post_rec_unlink,
531         [HOOK_MKNOD]   smfs_post_rec_create,
532         [HOOK_RENAME]  smfs_post_rec_rename,
533         [HOOK_SETATTR] smfs_post_rec_setattr,
534         [HOOK_WRITE]   smfs_post_rec_write,
535 };
536
537 int smfs_post_kml_rec(struct inode *dir, struct dentry *dst_dentry,
538                       void *data1, void *data2, int op)
539 {
540         if (smfs_kml_post[op]) {
541                 return smfs_kml_post[op](dir, dst_dentry, data1, data2);
542         }
543         return 0;
544 }