Whamcloud - gitweb
current branches now use lnet from HEAD
[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                              int flag)
53 {
54         struct filter_inode_info *i;
55         struct snap_cache *cache;
56         struct snapshot_operations *snapops; 
57
58         if (inode->i_filterdata || inode->i_ino & 0xF0000000)
59                 return;
60         cache = snap_find_cache(inode->i_dev);
61         if (!cache) {
62                 CERROR("currentfs_read_inode: cannot find cache\n");
63                 make_bad_inode(inode);
64                 return;
65         }
66         snapops = filter_c2csnapops(cache->cache_filter);
67
68         if (inode->i_filterdata) return;
69         
70         inode->i_filterdata = (struct filter_inode_info *) \
71                               kmem_cache_alloc(filter_info_cache, SLAB_KERNEL);
72         i = inode->i_filterdata;
73         i -> generation = snapops->get_generation(inode);
74         i -> flags      = flag;
75 }
76
77 void set_filter_ops(struct snap_cache *cache, struct inode *inode)
78 {
79         /* XXX now set the correct snap_{file,dir,sym}_iops */
80         if (S_ISDIR(inode->i_mode)) { 
81                 inode->i_op = filter_c2udiops(cache->cache_filter);
82                 inode->i_fop = filter_c2udfops(cache->cache_filter);
83         } else if (S_ISREG(inode->i_mode)) {
84                 if ( !filter_c2cfiops(cache->cache_filter) ) {
85                         filter_setup_file_ops(cache->cache_filter, inode, 
86                                               &currentfs_file_iops, 
87                                               &currentfs_file_fops, 
88                                               &currentfs_file_aops);
89                 }
90                 CDEBUG(D_INODE, "inode %lu, i_op at %p\n", 
91                        inode->i_ino, inode->i_op);
92                 inode->i_fop = filter_c2uffops(cache->cache_filter);
93                 inode->i_op = filter_c2ufiops(cache->cache_filter);
94                 if (inode->i_mapping)
95                         inode->i_mapping->a_ops = filter_c2ufaops(cache->cache_filter);
96
97         }
98         else if (S_ISLNK(inode->i_mode)) {
99                 if ( !filter_c2csiops(cache->cache_filter) ) {
100                         filter_setup_symlink_ops(cache->cache_filter, inode,
101                                 &currentfs_sym_iops, &currentfs_sym_fops);
102                 }
103                 inode->i_op = filter_c2usiops(cache->cache_filter);
104                 inode->i_fop = filter_c2usfops(cache->cache_filter);
105                 CDEBUG(D_INODE, "inode %lu, i_op at %p\n", 
106                        inode->i_ino, inode->i_op);
107         }
108 }
109 int currentfs_setxattr(struct dentry *dentry, const char *name, 
110                        const void *value, size_t size, int flags)
111 {
112         struct snap_cache       *cache;
113         struct inode            *inode = dentry->d_inode;
114         struct inode_operations *iops;
115         int    rc;
116
117         ENTRY;
118  
119         cache = snap_find_cache(inode->i_dev);
120         if (!cache) {
121                 CERROR("currentfs_setxattr: cannot find cache\n");
122                 RETURN(-EINVAL);
123         }
124
125         iops = filter_c2cfiops(cache->cache_filter);
126  
127         if (!iops || !iops->setxattr) {
128                 RETURN(-EINVAL);                
129         }
130         if ( snap_needs_cow(inode) != -1 ) {
131                 CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
132                 snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
133         }
134
135         rc = iops->setxattr(dentry, name, value, size, flags);
136
137         RETURN(rc);
138 }
139 int currentfs_removexattr(struct dentry *dentry, const char *name)
140 {
141         struct snap_cache       *cache;
142         struct inode            *inode = dentry->d_inode;
143         struct inode_operations *iops;
144         int    rc;
145
146         ENTRY;
147  
148         cache = snap_find_cache(inode->i_dev);
149         if (!cache) {
150                 CERROR("currentfs_setxattr: cannot find cache\n");
151                 RETURN(-EINVAL);
152         }
153
154         iops = filter_c2cfiops(cache->cache_filter);
155  
156         if (!iops || !iops->removexattr) {
157                 RETURN(-EINVAL);                
158         }
159         
160         if (snap_needs_cow(inode) != -1) {
161                 CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
162                 snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
163         }
164         rc = iops->removexattr(dentry, name);
165
166         RETURN(rc);
167 }
168
169 int currentfs_setattr(struct dentry *dentry, struct iattr *attr)
170 {
171         struct snap_cache       *cache;
172         struct inode            *inode = dentry->d_inode;
173         struct inode_operations *iops;
174         int    rc;
175
176         ENTRY;
177  
178         cache = snap_find_cache(inode->i_dev);
179         if (!cache) {
180                 CERROR("currentfs_setxattr: cannot find cache\n");
181                 RETURN(-EINVAL);
182         }
183
184         iops = filter_c2cfiops(cache->cache_filter);
185  
186         if (!iops || !iops->setattr) {
187                 RETURN(-EINVAL);                
188         }
189         if ( snap_needs_cow(inode) != -1 ) {
190                 CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
191                 snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
192         }
193
194         rc = iops->setattr(dentry, attr);
195
196         RETURN(rc);
197 }
198 /* Superblock operations. */
199 static void currentfs_read_inode(struct inode *inode)
200 {
201         struct snap_cache *cache;
202         ENTRY;
203
204         if( !inode ) 
205                 return;
206         CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
207
208         cache = snap_find_cache(inode->i_dev);
209         if (!cache) {
210                 CERROR("currentfs_read_inode: cannot find cache\n");
211                 make_bad_inode(inode);
212                 return;
213         }
214
215         if (inode->i_ino & 0xF0000000) { 
216                 currentfs_dotsnap_read_inode(cache, inode);
217                 return;
218         }
219
220         if(filter_c2csops(cache->cache_filter))
221                 filter_c2csops(cache->cache_filter)->read_inode(inode);
222
223         CDEBUG(D_INODE, "read_inode ino %lu icount %d \n", 
224                inode->i_ino, atomic_read(&inode->i_count));
225         set_filter_ops(cache, inode);
226         /*init filter_data struct 
227          * FIXME flag should be set future*/
228         init_filter_data(inode, 0); 
229         CDEBUG(D_INODE, "read_inode ino %lu icount %d \n", 
230                inode->i_ino, atomic_read(&inode->i_count));
231         return; 
232 }
233
234 static void currentfs_put_super(struct super_block *sb)
235 {
236
237         struct snap_cache *cache;
238         ENTRY;
239
240         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
241                 (ulong) sb, (ulong) sb->u.generic_sbp);
242         cache = snap_find_cache(sb->s_dev);
243
244         if (!cache) 
245                 GOTO(exit, 0);  
246         
247         /* handle COMPAT_FEATUREs */
248 #ifdef CONFIG_SNAPFS_EXT2
249         else if( cache->cache_type == FILTER_FS_EXT2 ){
250                 if( !EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_SNAPFS) ){
251                         sb->u.ext2_sb.s_feature_compat &=
252                                 ~EXT2_FEATURE_COMPAT_BLOCKCOW;
253                         sb->u.ext2_sb.s_es->s_feature_compat &=
254                                 cpu_to_le32(~EXT2_FEATURE_COMPAT_BLOCKCOW);
255                 }
256         }
257 #endif
258 #ifdef CONFIG_SNAPFS_EXT3
259         else if( cache->cache_type == FILTER_FS_EXT3 ){
260                 if( !EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_SNAPFS) ){
261                         sb->u.ext3_sb.s_es->s_feature_compat &=
262                                 cpu_to_le32(~EXT3_FEATURE_COMPAT_BLOCKCOW);
263                 }
264         }
265 #endif
266         /*
267          * If there is a saved 'put_super' function for the underlying
268          * fs then call it.
269          */
270         if (cache->cache_filter->o_caops.cache_sops->put_super) { 
271                 cache->cache_filter->o_caops.cache_sops->put_super(sb);
272         }
273         
274         if (!list_empty(&cache->cache_clone_list)) {
275                 CWARN("snap_put_super: clones exist!\n");
276         }
277
278         list_del(&cache->cache_chain);
279         snap_free_cache(cache);
280
281         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
282                 (ulong) sb, (ulong) sb->u.generic_sbp);
283 exit:
284         EXIT;
285         return;
286 }
287 static void currentfs_clear_inode(struct inode *inode)
288 {
289         struct snap_cache *cache;
290         struct super_operations *sops;
291         ENTRY;                                                                                                                                                                                                                       
292         cache = snap_find_cache(inode->i_dev);
293         if (!cache) {
294                 CDEBUG(D_INODE, "inode has invalid dev\n");
295                 return;
296         }
297         
298         if (inode->i_filterdata) {
299                 kmem_cache_free(filter_info_cache, inode->i_filterdata);
300                 inode->i_filterdata = NULL;
301         }
302
303         sops = filter_c2csops(cache->cache_filter);
304         if (sops && sops->clear_inode)
305                 sops->clear_inode(inode);
306 }
307
308 struct super_operations currentfs_super_ops = {
309         read_inode:     currentfs_read_inode,
310         put_super:      currentfs_put_super,
311         clear_inode:    currentfs_clear_inode,
312 };
313
314
315
316
317