Whamcloud - gitweb
add snapfs to cvs
[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 EXPORT_SYMTAB
9
10
11 #define __NO_VERSION__
12 #include <linux/module.h>
13 #include <asm/uaccess.h>
14 #include <linux/sched.h>
15 #include <linux/stat.h>
16 #include <linux/string.h>
17 #include <linux/locks.h>
18 #include <linux/quotaops.h>
19 #include <linux/list.h>
20 #include <linux/file.h>
21 #include <asm/bitops.h>
22 #include <asm/byteorder.h>
23
24 #ifdef CONFIG_SNAPFS_EXT2
25 #include <linux/ext2_fs.h>
26 #endif
27 #ifdef CONFIG_SNAPFS_EXT3
28 #include <linux/ext3_fs.h>
29 #endif
30
31 #include <linux/filter.h>
32 #include <linux/snapfs.h>
33 #include <linux/snapsupport.h>
34
35
36 extern int currentfs_remount(struct super_block * sb, int *flags, char *data);
37
38 /* XXX PJB: this is exactly what we need to put things under 
39    filters - we don't want the ext2 methods hardcoded, we want them
40    in the filter (in read_super) and then call those methods. 
41    See how InterMezzo gets the journal operations .
42 */
43  
44 extern void currentfs_dotsnap_read_inode(struct snap_cache *, struct inode *);
45
46 /* Superblock operations. */
47 static void currentfs_read_inode(struct inode *inode)
48 {
49         struct snap_cache *cache;
50         ENTRY;
51
52         if( !inode ) 
53         {
54                 EXIT;
55                 return;
56         }
57
58         CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
59
60         cache = snap_find_cache(inode->i_dev);
61         if ( !cache ) {
62                 printk("currentfs_read_inode: cannot find cache\n");
63                 make_bad_inode(inode);
64                 EXIT;
65                 return ;
66         }
67
68         if ( inode->i_ino & 0xF0000000 ) { 
69                 CDEBUG(D_INODE, "\n");
70                 currentfs_dotsnap_read_inode(cache, inode);
71                 EXIT;
72                 return ;
73         }
74
75         if( filter_c2csops(cache->cache_filter) )
76                 filter_c2csops(cache->cache_filter)->read_inode(inode);
77
78         /* XXX now set the correct snap_{file,dir,sym}_iops */
79         if ( S_ISDIR(inode->i_mode) ) 
80                 inode->i_op = filter_c2udiops(cache->cache_filter);
81         else if ( S_ISREG(inode->i_mode) ) {
82                 if ( !filter_c2cfiops(cache->cache_filter) ) {
83                         filter_setup_file_ops(cache->cache_filter,
84                                 inode->i_op, &currentfs_file_iops);
85                 }
86                 inode->i_op = filter_c2ufiops(cache->cache_filter);
87                 printk("inode %lu, i_op at %p\n", inode->i_ino, inode->i_op);
88         }
89         else if ( S_ISLNK(inode->i_mode) ) {
90                 if ( !filter_c2csiops(cache->cache_filter) ) {
91                         filter_setup_symlink_ops(cache->cache_filter,
92                                 inode->i_op, &currentfs_sym_iops);
93                 }
94                 inode->i_op = filter_c2usiops(cache->cache_filter);
95                 printk("inode %lu, i_op at %p\n", inode->i_ino, inode->i_op);
96         }
97
98         EXIT;
99         return; 
100 }
101
102
103 static int currentfs_notify_change(struct dentry *dentry, struct iattr *iattr)
104 {
105         struct snap_cache *cache;
106         int rc;
107         struct super_operations *sops;
108
109         ENTRY;
110
111         if (currentfs_is_under_dotsnap(dentry)) {
112                 EXIT;
113                 return -EPERM;
114         }
115
116         cache = snap_find_cache(dentry->d_inode->i_dev);
117         if ( !cache ) { 
118                 EXIT;
119                 return -EINVAL;
120         }
121
122         /* XXX better alloc a new dentry */
123
124         if ( snap_needs_cow(dentry->d_inode) != -1 ) {
125                 printk("notify_change:snap_needs_cow for ino %lu \n",
126                         dentry->d_inode->i_ino);
127                 snap_do_cow(dentry->d_inode, 
128                         dentry->d_parent->d_inode->i_ino, 0);
129         }
130
131         sops = filter_c2csops(cache->cache_filter); 
132         if (!sops ||
133             !sops->notify_change) {
134                 EXIT;
135                 return -EINVAL;
136         }
137         rc = sops->notify_change(dentry, iattr);
138         
139         EXIT;
140         return rc;
141 }
142
143
144 static void currentfs_put_super(struct super_block *sb)
145 {
146
147         struct snap_cache *cache;
148         ENTRY;
149
150         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
151                 (ulong) sb, (ulong) sb->u.generic_sbp);
152         cache = snap_find_cache(sb->s_dev);
153         if (!cache) {
154                 EXIT;
155                 goto exit;
156         }
157         /* handle COMPAT_FEATUREs */
158 #ifdef CONFIG_SNAPFS_EXT2
159         else if( cache->cache_type == FILTER_FS_EXT2 ){
160                 if( !EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_SNAPFS) ){
161                         sb->u.ext2_sb.s_feature_compat &=
162                                 ~EXT2_FEATURE_COMPAT_BLOCKCOW;
163                         sb->u.ext2_sb.s_es->s_feature_compat &=
164                                 cpu_to_le32(~EXT2_FEATURE_COMPAT_BLOCKCOW);
165                 }
166         }
167 #endif
168 #ifdef CONFIG_SNAPFS_EXT3
169         else if( cache->cache_type == FILTER_FS_EXT3 ){
170                 if( !EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_SNAPFS) ){
171                         sb->u.ext3_sb.s_es->s_feature_compat &=
172                                 cpu_to_le32(~EXT3_FEATURE_COMPAT_BLOCKCOW);
173                 }
174         }
175 #endif
176         /*
177          * If there is a saved 'put_super' function for the underlying
178          * fs then call it.
179          */
180         if (cache->cache_filter->o_caops.cache_sops->put_super) { 
181                 cache->cache_filter->o_caops.cache_sops->put_super(sb);
182         }
183         
184         if (!list_empty(&cache->cache_clone_list)) {
185                 printk("Warning: snap_put_super: clones exist!\n");
186         }
187
188         list_del(&cache->cache_chain);
189         snap_free_cache(cache);
190
191         CDEBUG(D_SUPER, "sb %lx, sb->u.generic_sbp: %lx\n",
192                 (ulong) sb, (ulong) sb->u.generic_sbp);
193 exit:
194         CDEBUG(D_MALLOC, "after umount: kmem %ld, vmem %ld\n",
195                snap_kmemory, snap_vmemory);
196         MOD_DEC_USE_COUNT;
197         EXIT;
198         return ;
199 }
200
201 struct super_operations currentfs_super_ops = {
202         currentfs_read_inode,
203         NULL, /* write inode */
204         NULL, /* put inode */
205         NULL, /* delete inode */
206         currentfs_notify_change,
207         currentfs_put_super,
208         NULL, /* write super */
209         NULL,
210         NULL, /* remount */
211 };