Whamcloud - gitweb
8a43df7f324b4e131e543c7288052a8f0ea4a9f2
[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         CDEBUG(D_INFO, "trans commit %p\n", fsfilt->fs_commit);
76
77         if (fsfilt->fs_commit)
78                 fsfilt->fs_commit(inode, handle, force_sync);
79 }
80
81 /*smfs_path is gotten from intermezzo*/
82 static char* smfs_path(struct dentry *dentry, struct dentry *root, char *buffer,
83                        int buflen)
84 {
85         char * end = buffer + buflen;
86         char * name = buffer;
87         char * buf_end = buffer + buflen;
88         char * retval;
89
90         *--end = '\0';
91         buflen--;
92         /* Get '/' right */
93         retval = end-1;
94         *retval = '/';
95
96         for (;;) {
97                 struct dentry * parent;
98                 int namelen;
99
100                 if (dentry == root)
101                         break;
102                 parent = dentry->d_parent;
103                 if (dentry == parent)
104                         break;
105                 namelen = dentry->d_name.len;
106                 buflen -= namelen + 1;
107                 if (buflen < 0)
108                         break;
109                 end -= namelen;
110                 memcpy(end, dentry->d_name.name, namelen);
111                 *--end = '/';
112                 retval = end;
113                 dentry = parent;
114         }
115         
116         while (end != buf_end) 
117                 *name++ = *end++;
118         *name = '\0'; 
119         return retval;
120 }
121
122 static int smfs_log_path(struct super_block *sb, 
123                          struct dentry *dentry, 
124                          char   *buffer,
125                          int    buffer_len)
126 {
127         struct dentry *root=sb->s_root;
128         char *p_name = buffer + sizeof(int);
129         char *name = NULL;
130         int namelen = 0;
131         if (dentry) {
132                 name = smfs_path(dentry, root, p_name, buffer_len - sizeof(int));
133                 namelen = cpu_to_le32(strlen(p_name));
134                 memcpy(buffer, &namelen, sizeof(int));        
135         }
136         namelen += sizeof(int);
137         RETURN(namelen);
138 }
139
140 static inline int log_it(char *buffer, void *data, int length)
141 {
142         memcpy(buffer, &length, sizeof(int));
143         memcpy(buffer + sizeof(int), data, length);
144         return (sizeof(int) + length);                 
145 }
146
147 static int smfs_pack_rec (char *buffer, struct dentry *dentry, 
148                           struct inode *dir, void *data1, 
149                           void *data2, int op)
150
151         smfs_pack_rec_func pack_func;        
152         int rc;
153
154         pack_func = smfs_get_rec_pack_type(dir->i_sb);
155         if (!pack_func) {
156                 return (0);
157         }
158         rc = pack_func(buffer, dentry, dir, data1, data2, op);
159         return rc;
160 }
161
162 static int smfs_post_rec_create(struct inode *dir, 
163                                 struct dentry *dentry,
164                                  void   *data1,
165                                 void   *data2)
166 {
167         struct smfs_super_info *sinfo;
168         char   *buffer = NULL, *pbuf;
169         int rc = 0, length = 0, buf_len = 0;
170         
171         sinfo = S2SMI(dentry->d_inode->i_sb);
172         if (!sinfo)
173                 RETURN(-EINVAL);
174         
175         OBD_ALLOC(buffer, PAGE_SIZE);
176         if (!buffer)
177                 GOTO(exit, rc = -ENOMEM);        
178
179         buf_len = PAGE_SIZE;
180         KML_BUF_REC_INIT(buffer, pbuf, buf_len);
181         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
182         if (rc < 0)
183                 GOTO(exit, rc);
184         length = rc;
185         KML_BUF_REC_END(buffer, length, pbuf);   
186        
187         rc = smfs_pack_rec(pbuf, dentry, dir, 
188                            data1, data2, REINT_CREATE);
189         if (rc <= 0)
190                 GOTO(exit, rc);
191         else
192                 length += rc;
193         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
194 exit:
195         if (buffer)
196                 OBD_FREE(buffer, PAGE_SIZE);        
197         
198         RETURN(rc);
199 }
200
201 static int smfs_post_rec_link(struct inode *dir, 
202                               struct dentry *dentry,
203                                void   *data1,
204                               void   *data2)
205 {
206         struct smfs_super_info *sinfo;
207         struct dentry *old_dentry = (struct dentry *)data1;
208         char *buffer = NULL, *pbuf = NULL;
209         int rc = 0, length = 0, buf_len = 0;
210         
211         sinfo = S2SMI(dir->i_sb);
212         if (!sinfo)
213                 RETURN(-EINVAL);
214         OBD_ALLOC(buffer, PAGE_SIZE);
215         if (!buffer)
216                 GOTO(exit, rc = -ENOMEM);
217         
218         buf_len = PAGE_SIZE;
219         KML_BUF_REC_INIT(buffer, pbuf, buf_len);
220         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
221         if (rc < 0)
222                 GOTO(exit, rc);
223         
224         length = rc;
225         KML_BUF_REC_END(buffer, length, pbuf);  
226         
227         rc = smfs_pack_rec(pbuf, dentry, dir, dentry->d_parent, 
228                            old_dentry->d_parent, REINT_LINK);
229         if (rc <= 0)
230                 GOTO(exit, rc);
231         else
232                 length += rc;
233         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
234 exit:
235         if (buffer)
236                 OBD_FREE(buffer, PAGE_SIZE);        
237         
238         RETURN(rc);
239 }
240
241 static int smfs_post_rec_unlink(struct inode *dir, struct dentry *dentry,
242                                 void *data1, void *data2)
243 {
244         struct smfs_super_info *sinfo;
245         int mode = *((int*)data1);
246         char   *buffer = NULL, *pbuf = NULL;
247         int  length = 0, rc = 0, buf_len = 0;
248          
249         sinfo = S2SMI(dentry->d_inode->i_sb);
250         if (!sinfo)
251                 RETURN(-EINVAL);
252         
253         OBD_ALLOC(buffer, PAGE_SIZE);
254         if (!buffer)
255                 GOTO(exit, rc = -ENOMEM);        
256       
257         buf_len = PAGE_SIZE;
258         KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
259         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
260         if (rc < 0)
261                 GOTO(exit, rc);
262
263         length = rc;
264         KML_BUF_REC_END(buffer, length, pbuf);
265         rc = smfs_pack_rec(pbuf, dentry, dir, 
266                            &mode, NULL, REINT_UNLINK);
267         if (rc <= 0)
268                 GOTO(exit, rc);
269         else
270                 length += rc;         
271         
272         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
273 exit:
274         if (buffer)
275                 OBD_FREE(buffer, PAGE_SIZE);        
276         
277         RETURN(rc);
278 }
279
280 static int smfs_post_rec_rename(struct inode *dir, 
281                                  struct dentry *dentry,
282                                  void   *data1,
283                                 void   *data2)
284 {
285         struct smfs_super_info *sinfo;
286         struct inode *new_dir = (struct inode *)data1;
287         struct dentry *new_dentry = (struct dentry *)data2;
288         char *buffer = NULL, *pbuf = NULL;
289         int rc = 0, length = 0, buf_len = 0;
290         
291         sinfo = S2SMI(dir->i_sb);
292         if (!sinfo)
293                 RETURN(-EINVAL);
294
295         OBD_ALLOC(buffer, PAGE_SIZE);
296         if (!buffer)
297                 GOTO(exit, rc = -ENOMEM);
298         
299         buf_len = PAGE_SIZE;
300         KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
301         rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
302         if (rc < 0)
303                 GOTO(exit, rc);
304
305         pbuf += rc; 
306         length += rc;
307         buf_len -= rc;         
308         /*record new_dentry path*/        
309         rc = smfs_log_path(dir->i_sb, new_dentry, pbuf, buf_len);
310         if (rc < 0)
311                 GOTO(exit, rc);
312
313         length += rc;
314         KML_BUF_REC_END(buffer, length, pbuf);
315                
316         rc = smfs_pack_rec(pbuf, dentry, dir, 
317                            new_dir, new_dentry, REINT_RENAME);
318         if (rc <= 0) 
319                 GOTO(exit, rc);
320         length += rc;
321         
322         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
323 exit:
324         if (buffer)
325                 OBD_FREE(buffer, PAGE_SIZE);
326         RETURN(rc);
327 }
328
329 static int smfs_insert_extents_ea(struct inode *inode, size_t from, loff_t num)
330 {
331         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
332         int rc = 0;
333         
334         if (SMFS_INODE_OVER_WRITE(inode))
335                 RETURN(rc);
336         
337         rc = fsfilt->fs_insert_extents_ea(inode, OFF2BLKS(from, inode), 
338                                           SIZE2BLKS(num, inode));        
339         RETURN(rc);
340 }
341
342 static int smfs_remove_extents_ea(struct inode *inode, size_t from, loff_t num)
343 {
344         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
345         int rc = 0;
346         
347         rc = fsfilt->fs_remove_extents_ea(inode, OFF2BLKS(from, inode), 
348                                           SIZE2BLKS(num, inode));        
349         
350         RETURN(rc);
351 }
352
353 static int smfs_remove_all_extents_ea(struct inode *inode)
354 {
355         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
356         int rc = 0;
357         
358         rc = fsfilt->fs_remove_extents_ea(inode, 0, 0xffffffff);        
359         RETURN(rc);
360 }
361 static int  smfs_init_extents_ea(struct inode *inode)
362 {
363         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
364         int rc = 0;
365         
366         rc = fsfilt->fs_init_extents_ea(inode);        
367         
368         RETURN(rc);
369 }
370 static int smfs_set_dirty_flags(struct inode *inode, int flags)
371 {
372         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
373         void   *handle;
374         int    rc = 0;
375
376         if (SMFS_INODE_OVER_WRITE(inode))
377                 RETURN(rc);
378         /*FIXME later, the blocks needed in journal here will be recalculated*/
379          handle = smfs_trans_start(inode, FSFILT_OP_SETATTR, NULL);
380         if (IS_ERR(handle)) {
381                 CERROR("smfs_set_dirty_flag:no space for transaction\n");
382                 RETURN(-ENOSPC);
383         }
384         if ((!SMFS_INODE_DIRTY_WRITE(inode) && (!SMFS_INODE_OVER_WRITE(inode))) || 
385              ((flags == SMFS_OVER_WRITE) && (SMFS_INODE_DIRTY_WRITE(inode)))) {        
386                 rc = fsfilt->fs_set_xattr(inode, handle, REINT_EXTENTS_FLAGS,
387                                             &flags, sizeof(int));
388                 if (rc)
389                         GOTO(out, rc);
390         }
391         if (flags == SMFS_OVER_WRITE)
392                 SMFS_SET_INODE_OVER_WRITE(inode);
393         else
394                 SMFS_SET_INODE_DIRTY_WRITE(inode);
395 out:
396         smfs_trans_commit(inode, handle, 0);
397         RETURN(rc);
398 }
399
400 int smfs_post_rec_setattr(struct inode *inode, struct dentry *dentry,
401                           void  *data1, void  *data2)
402 {        
403         struct smfs_super_info *sinfo;
404         struct iattr *attr = (struct iattr *)data1;
405         char   *buffer = NULL, *pbuf;
406         int rc = 0, length = 0, buf_len = 0;
407
408         sinfo = S2SMI(inode->i_sb);
409         if (!sinfo)
410                 RETURN(-EINVAL);
411         
412         OBD_ALLOC(buffer, PAGE_SIZE);
413         if (!buffer)
414                 GOTO(exit, rc = -ENOMEM);        
415
416         buf_len = PAGE_SIZE;
417         KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
418         rc = smfs_log_path(inode->i_sb, dentry, pbuf, buf_len);
419         if (rc < 0)
420                 GOTO(exit, rc);
421         
422         length = rc;
423         KML_BUF_REC_END(buffer, length, pbuf);
424         
425         rc = smfs_pack_rec(pbuf, dentry, inode, 
426                            data1, data2, REINT_SETATTR);
427         if (rc <= 0) 
428                 GOTO(exit, rc);
429         else
430                 length += rc;
431
432         rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
433         if (!rc) {
434                 if (attr && attr->ia_valid & ATTR_SIZE) {
435                         smfs_remove_extents_ea(inode, attr->ia_size,
436                                                0xffffffff);                                
437                         if (attr->ia_size == 0)
438                                 smfs_set_dirty_flags(inode, SMFS_OVER_WRITE);
439                         else
440                                 smfs_set_dirty_flags(inode, SMFS_DIRTY_WRITE);
441                 }
442         }
443 exit:
444         if (buffer)
445                 OBD_FREE(buffer, PAGE_SIZE);        
446         RETURN(rc);
447 }
448  
449 static int all_blocks_present_ea(struct inode *inode)
450 {
451         int rc = 0;
452         
453         RETURN(rc);        
454 }
455 int smfs_post_rec_write(struct inode *dir, struct dentry *dentry,
456                         void   *data1, void *data2)
457 {
458         struct smfs_super_info *sinfo;
459         char   *buffer = NULL, *pbuf;
460         int rc = 0, length = 0, buf_len = 0;
461         
462         if (!SMFS_INODE_OVER_WRITE(dentry->d_inode) && 
463             !SMFS_INODE_DIRTY_WRITE(dentry->d_inode)) {
464                 sinfo = S2SMI(dentry->d_inode->i_sb);
465                 if (!sinfo)
466                         RETURN(-EINVAL);
467                 
468                 OBD_ALLOC(buffer, PAGE_SIZE);
469                 if (!buffer)
470                         GOTO(exit, rc = -ENOMEM);        
471                 
472                 buf_len = PAGE_SIZE;
473                 KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
474                 rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
475                 
476                 if (rc < 0)
477                         GOTO(exit, rc);
478                 pbuf += rc;
479                 memcpy(buffer, &rc, sizeof(int));        
480                 length = rc + sizeof(int);
481                         
482                 rc = smfs_pack_rec(pbuf, dentry, dir, 
483                                    data1, data2, REINT_WRITE);
484                 if (rc <= 0) 
485                         GOTO(exit, rc);
486                 else
487                         length += rc;
488  
489                 rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
490                 if (rc)
491                         GOTO(exit, rc);
492                 rc = smfs_init_extents_ea(dentry->d_inode);
493                 if (rc)
494                         GOTO(exit, rc);
495         } 
496         if (dentry->d_inode->i_size == 0) {
497                 smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);        
498         } else {
499                 /*insert extent EA*/
500                 loff_t off = *((loff_t*)data1);        
501                 size_t count = *((size_t*)data2);
502                 
503                 rc = smfs_insert_extents_ea(dentry->d_inode, off, count);        
504                 if (rc < 0)  
505                         GOTO(exit, rc);        
506                 if (all_blocks_present_ea(dentry->d_inode)){
507                         smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);        
508                         smfs_remove_all_extents_ea(dentry->d_inode);
509                 } else {
510                         smfs_set_dirty_flags(dentry->d_inode, SMFS_DIRTY_WRITE);        
511                 }
512         }
513 exit:
514         if (buffer)
515                 OBD_FREE(buffer, PAGE_SIZE);
516         RETURN(rc);
517 }
518
519 typedef int (*post_kml_rec)(struct inode *dir, struct dentry *dentry,
520                             void *data1, void *data2);
521
522 static post_kml_rec smfs_kml_post[REINT_MAX + 1] = {
523         [REINT_SETATTR] smfs_post_rec_setattr,
524         [REINT_CREATE]  smfs_post_rec_create,
525         [REINT_LINK]    smfs_post_rec_link,
526         [REINT_UNLINK]  smfs_post_rec_unlink,
527         [REINT_RENAME]  smfs_post_rec_rename,
528         [REINT_WRITE]   smfs_post_rec_write,
529 };
530
531 int smfs_post_kml_rec(struct inode *dir, struct dentry *dst_dentry,
532                       void *data1, void *data2, int op)
533 {
534         return smfs_kml_post[op](dir, dst_dentry, data1, data2);
535 }