Whamcloud - gitweb
port snapfs to 2.4
[fs/lustre-release.git] / lustre / snapfs / inode.c
1 /*
2  *  fs/snap/snap.c
3  *
4  *  A snap shot file system.
5  *
6  */
7
8 #define DEBUG_SUBSYSTEM S_SNAP
9
10 #include <linux/kmod.h>
11 #include <linux/init.h>
12 #include <linux/fs.h>
13 #include <linux/slab.h>
14 #include <linux/jbd.h>
15 #include <linux/ext3_fs.h>
16 #include <linux/string.h>
17 #include <linux/snap.h>
18 #include "snapfs_internal.h" 
19
20
21 extern int currentfs_remount(struct super_block * sb, int *flags, char *data);
22
23 /* XXX PJB: this is exactly what we need to put things under 
24    filters - we don't want the ext2 methods hardcoded, we want them
25    in the filter (in read_super) and then call those methods. 
26    See how InterMezzo gets the journal operations .
27 */
28  
29 extern void currentfs_dotsnap_read_inode(struct snap_cache *, struct inode *);
30
31 static kmem_cache_t *filter_info_cache = NULL;
32
33 void cleanup_filter_info_cache()
34 {
35         kmem_cache_destroy(filter_info_cache);
36 }
37
38 int init_filter_info_cache()
39 {
40         filter_info_cache = kmem_cache_create("snapfs_filter_info",
41                                                sizeof(struct filter_inode_info), 
42                                             0, 0, NULL, NULL);
43         if (!filter_info_cache) {
44                 CERROR("unable to create snap_inode info cache\n");
45                 return -ENOMEM;
46         }
47         return 0;
48 }
49
50
51 void init_filter_data(struct inode *inode, 
52                              struct snapshot_operations *snapops, 
53                              int flag)
54 {
55         struct filter_inode_info *i;
56
57         if (inode->i_filterdata){
58                 return;
59         }
60         inode->i_filterdata = (struct filter_inode_info *) \
61                               kmem_cache_alloc(filter_info_cache, SLAB_KERNEL);
62         i = inode->i_filterdata;
63         i -> generation = snapops->get_generation(inode);
64         i -> flags      = flag;
65 }
66 /* Superblock operations. */
67 static void currentfs_read_inode(struct inode *inode)
68 {
69         struct snap_cache *cache;
70         struct snapshot_operations *snapops;    
71         ENTRY;
72
73         if( !inode ) 
74                 return;
75
76         CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
77
78         cache = snap_find_cache(inode->i_dev);
79         if (!cache) {
80                 CERROR("currentfs_read_inode: cannot find cache\n");
81                 make_bad_inode(inode);
82                 return;
83         }
84
85         if (inode->i_ino & 0xF0000000) { 
86                 currentfs_dotsnap_read_inode(cache, inode);
87                 return;
88         }
89         snapops = filter_c2csnapops(cache->cache_filter);
90         
91         if (!snapops || !snapops->get_indirect) 
92                 return;
93
94         if(filter_c2csops(cache->cache_filter))
95                 filter_c2csops(cache->cache_filter)->read_inode(inode);
96
97         /* XXX now set the correct snap_{file,dir,sym}_iops */
98         if (S_ISDIR(inode->i_mode)) 
99                 inode->i_op = filter_c2udiops(cache->cache_filter);
100         else if (S_ISREG(inode->i_mode)) {
101                 if ( !filter_c2cfiops(cache->cache_filter) ) {
102                         filter_setup_file_ops(cache->cache_filter, inode, 
103                                               &currentfs_file_iops, 
104                                               &currentfs_file_fops, 
105                                               &currentfs_file_aops);
106                 }
107                 CDEBUG(D_INODE, "inode %lu, i_op at %p\n", 
108                        inode->i_ino, inode->i_op);
109         }
110         else if (S_ISLNK(inode->i_mode)) {
111                 if ( !filter_c2csiops(cache->cache_filter) ) {
112                         filter_setup_symlink_ops(cache->cache_filter, inode,
113                                 &currentfs_sym_iops, &currentfs_sym_fops);
114                 }
115                 inode->i_op = filter_c2usiops(cache->cache_filter);
116                 CDEBUG(D_INODE, "inode %lu, i_op at %p\n", 
117                        inode->i_ino, inode->i_op);
118         }
119         /*init filter_data struct 
120          * FIXME flag should be set future*/
121         init_filter_data(inode, snapops, 0); 
122         return; 
123 }
124
125 static void currentfs_put_super(struct super_block *sb)
126 {
127
128         struct snap_cache *cache;
129         ENTRY;
130
131         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
132                 (ulong) sb, (ulong) sb->u.generic_sbp);
133         cache = snap_find_cache(sb->s_dev);
134
135         if (!cache) 
136                 GOTO(exit, 0);  
137         
138         /* handle COMPAT_FEATUREs */
139 #ifdef CONFIG_SNAPFS_EXT2
140         else if( cache->cache_type == FILTER_FS_EXT2 ){
141                 if( !EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_SNAPFS) ){
142                         sb->u.ext2_sb.s_feature_compat &=
143                                 ~EXT2_FEATURE_COMPAT_BLOCKCOW;
144                         sb->u.ext2_sb.s_es->s_feature_compat &=
145                                 cpu_to_le32(~EXT2_FEATURE_COMPAT_BLOCKCOW);
146                 }
147         }
148 #endif
149 #ifdef CONFIG_SNAPFS_EXT3
150         else if( cache->cache_type == FILTER_FS_EXT3 ){
151                 if( !EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_SNAPFS) ){
152                         sb->u.ext3_sb.s_es->s_feature_compat &=
153                                 cpu_to_le32(~EXT3_FEATURE_COMPAT_BLOCKCOW);
154                 }
155         }
156 #endif
157         /*
158          * If there is a saved 'put_super' function for the underlying
159          * fs then call it.
160          */
161         if (cache->cache_filter->o_caops.cache_sops->put_super) { 
162                 cache->cache_filter->o_caops.cache_sops->put_super(sb);
163         }
164         
165         if (!list_empty(&cache->cache_clone_list)) {
166                 CWARN("snap_put_super: clones exist!\n");
167         }
168
169         list_del(&cache->cache_chain);
170         snap_free_cache(cache);
171
172         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
173                 (ulong) sb, (ulong) sb->u.generic_sbp);
174 exit:
175         EXIT;
176         return;
177 }
178 static void currentfs_clear_inode(struct inode *inode)
179 {
180         struct snap_cache *cache;
181         struct super_operations *sops;
182         ENTRY;                                                                                                                                                                                                                       
183         cache = snap_find_cache(inode->i_dev);
184         if (!cache) {
185                 CDEBUG(D_INODE, "inode has invalid dev\n");
186                 return;
187         }
188         
189         if (inode->i_filterdata) {
190                 kmem_cache_free(filter_info_cache, inode->i_filterdata);
191                 inode->i_filterdata = NULL;
192         }
193
194         sops = filter_c2csops(cache->cache_filter);
195         if (sops && sops->clear_inode)
196                 sops->clear_inode(inode);
197 }
198
199 struct super_operations currentfs_super_ops = {
200         read_inode:     currentfs_read_inode,
201         put_super:      currentfs_put_super,
202         clear_inode:    currentfs_clear_inode,
203 };