Whamcloud - gitweb
current branches now use lnet from HEAD
[fs/lustre-release.git] / lustre / snapfs / snap.c
1
2 /*
3  *  fs/snap/snap.c
4  *
5  *  A snap shot file system.
6  *
7  */
8
9 #define DEBUG_SUBSYSTEM S_SNAP
10
11 #include <linux/kmod.h>
12 #include <linux/init.h>
13 #include <linux/fs.h>
14 #include <linux/slab.h>
15 #include <linux/string.h>
16 #include <linux/snap.h>
17 #include "snapfs_internal.h" 
18
19 /*
20  * Return true if the inode is a redirector inode.
21  */
22 int snap_is_redirector(struct inode *cache_inode)
23 {
24         struct snap_cache *cache;
25         struct snapshot_operations *snapops;
26
27         cache = snap_find_cache(cache_inode->i_dev);
28         if (!cache) {
29                 return 0;
30         }
31         snapops = filter_c2csnapops(cache->cache_filter);
32         if (!snapops || !snapops->is_redirector) {
33                 return 0;
34         }
35
36         CDEBUG(D_SNAP, "ino %ld\n", cache_inode->i_ino);
37         return snapops->is_redirector(cache_inode);
38 }
39
40 /*
41  * Using a cache inode and clone super block find the real one.
42  */
43 struct inode *snap_redirect(struct inode *cache_inode, 
44                             struct super_block *clone_sb)
45 {
46         struct snap_clone_info *clone_info;
47         struct snap_table *table;
48         struct inode *redirected;
49         struct snap_cache *cache;
50         struct snapshot_operations *snapops;
51         int slot = 0;
52         int my_table[SNAP_MAX];
53         int clone_slot;
54
55         ENTRY;
56
57         cache = snap_find_cache(cache_inode->i_dev);
58         if (!cache) {
59                 RETURN(NULL);
60         }
61         snapops = filter_c2csnapops(cache->cache_filter);
62         if (!snapops || !snapops->get_indirect) {
63                 RETURN(NULL);
64         }
65
66         CDEBUG(D_SNAP, "cache ino %ld\n", cache_inode->i_ino);
67         clone_info = (struct snap_clone_info *)&clone_sb->u.generic_sbp;
68
69         table = &snap_tables[clone_info->clone_cache->cache_snap_tableno];
70
71         /* first find if there are indirected at the clone_index */
72         redirected = snapops->get_indirect(cache_inode, NULL, 
73                                            clone_info->clone_index);
74         /* if not found, get the FIRST index after this and before NOW */
75         /* XXX fix this later, now use tbl_count, not NOW */
76         if (!redirected) {
77                 int index;
78
79                 memset(my_table, 0, sizeof(my_table));
80                 clone_slot = snap_index2slot(table, clone_info->clone_index);
81                 for (slot = table->tbl_count-1; slot >= clone_slot; slot --) {
82                         my_table[slot - clone_slot + 1] = table->snap_items[slot].index;
83                 }
84                 index = table->tbl_count - clone_slot;
85                 redirected = snapops->get_indirect(cache_inode, my_table, index);
86         }
87
88         if (redirected) 
89                 CDEBUG(D_SNAP,"redirected ino %ld\n",redirected->i_ino);
90
91         return redirected;
92 }
93
94 /*
95  * Make a copy of the data and plug a redirector in between if there
96  * is no redirector yet.
97  */
98 int snap_do_cow(struct inode *inode, ino_t parent_ino, int del)
99 {
100         struct snap_cache *cache;
101         struct snap snap;
102         struct inode *ind = NULL;
103         struct snapshot_operations *snapops;
104
105         ENTRY;
106         CDEBUG(D_SNAP, "snap_do_cow, ino %ld\n", inode->i_ino);
107
108         cache = snap_find_cache(inode->i_dev);
109         if (!cache) {
110                 RETURN(-EINVAL);
111         }
112         snapops = filter_c2csnapops(cache->cache_filter);
113         if (!snapops || !snapops->create_indirect) {
114                 RETURN(-EINVAL);
115         }
116
117         snap_last(cache, &snap);
118         ind = snapops->create_indirect(inode, snap.index, snap.gen, parent_ino, del);
119         if(!ind)
120                 RETURN(-EINVAL);                
121         init_filter_data(ind, 0);
122         set_filter_ops(cache, ind);             
123         iput(ind);
124         RETURN(0);
125 }
126
127 int snap_iterate(struct super_block *sb,
128                 int (*repeat)(struct inode *inode, void *priv),
129                 struct inode **start, void *priv, int flag)
130 {
131         struct inode *inode = sb->s_root->d_inode;
132         struct snap_cache *cache;
133         struct snapshot_operations *snapops;
134
135         ENTRY;
136
137         cache = snap_find_cache(inode->i_dev);
138         if (!cache) {
139                 RETURN(0);
140         }
141         snapops = filter_c2csnapops(cache->cache_filter);
142         if (!snapops || !snapops->iterate) {
143                 RETURN(0);
144         }
145
146         return snapops->iterate(sb, repeat, start, priv, flag);
147 }
148
149 int snap_destroy_indirect(struct inode *pri, int index, struct inode *next_ind )
150 {
151         struct snap_cache *cache;
152         struct snapshot_operations *snapops;
153
154         ENTRY;
155         cache = snap_find_cache(pri->i_dev);
156         if (!cache) 
157                 RETURN(0);
158         snapops = filter_c2csnapops(cache->cache_filter);
159         if (!snapops || !snapops->destroy_indirect) 
160                 RETURN(0);
161
162         return snapops->destroy_indirect(pri, index, next_ind);
163 }
164
165 int snap_restore_indirect(struct inode *pri, int index )
166 {
167         struct snap_cache *cache;
168         struct snapshot_operations *snapops;
169
170         ENTRY;
171
172         cache = snap_find_cache(pri->i_dev);
173         if (!cache) 
174                 RETURN(0);
175
176         snapops = filter_c2csnapops(cache->cache_filter);
177         if (!snapops || !snapops->restore_indirect) 
178                 RETURN(0);
179
180         return snapops->restore_indirect(pri, index);
181 }
182
183 struct inode *snap_get_indirect(struct inode *pri, int *table, int slot)
184 {
185         struct snap_cache *cache;
186         struct snapshot_operations *snapops;
187
188         ENTRY;
189
190         cache = snap_find_cache(pri->i_dev);
191         if (!cache) 
192                 RETURN(NULL);
193         
194         snapops = filter_c2csnapops(cache->cache_filter);
195         if (!snapops || !snapops->get_indirect) 
196                 RETURN(NULL);
197
198         return snapops->get_indirect(pri, table, slot);
199 }
200
201 int snap_set_indirect(struct inode *pri, ino_t ind_ino, int index, ino_t parent_ino)
202 {
203         struct snap_cache *cache;
204         struct snapshot_operations *snapops;
205
206         ENTRY;
207
208         cache = snap_find_cache(pri->i_dev);
209         if (!cache) 
210                 RETURN(-EINVAL);
211         
212         snapops = filter_c2csnapops(cache->cache_filter);
213         if (!snapops || !snapops->set_indirect) 
214                 RETURN(-EINVAL);
215
216         EXIT;
217         return snapops->set_indirect(pri, ind_ino, index, parent_ino);
218 }
219
220