Whamcloud - gitweb
current branches now use lnet from HEAD
[fs/lustre-release.git] / lustre / snapfs / dotsnap.c
1 /*
2  * dotsnap.c - support for .snap directories
3  */
4
5 #define DEBUG_SUBSYSTEM S_SNAP
6
7 #include <linux/module.h>
8 #include <linux/kernel.h>
9 #include <linux/string.h>
10 #include <linux/slab.h>
11 #include <linux/stat.h>
12 #include <linux/unistd.h>
13 #include <linux/jbd.h>
14 #include <linux/ext3_fs.h>
15 #include <linux/snap.h>
16
17 #include "snapfs_internal.h" 
18
19 struct inode_operations dotsnap_inode_operations;
20 struct file_operations dotsnap_file_operations;
21
22 int currentfs_is_under_dotsnap(struct dentry *de) 
23 {
24         int index = 0;
25
26         while(de && de->d_parent != de) {
27                 if ( de->d_inode && de->d_inode->i_ino & 0xF0000000 ) {
28                         EXIT;
29                         return index;
30                 }
31                 index = (int)de->d_fsdata;
32                 de = de->d_parent;
33         }
34
35         RETURN(0);
36 }
37
38 void currentfs_dotsnap_read_inode(struct snap_cache *cache, 
39                                   struct inode *inode)
40 {
41         int tableno = cache->cache_snap_tableno; 
42         struct snap_table *table; 
43         ENTRY;
44
45         table = &snap_tables[tableno];
46
47         inode->i_mode = S_IFDIR | 0755 ;
48         inode->i_op = &dotsnap_inode_operations;
49         inode->i_size = table->tbl_count - 1; 
50         /* all except current form a subdirectory and . and .. */
51         inode->i_nlink = table->tbl_count -1 + 2;
52         inode->i_uid = 0;
53         inode->i_gid = 0;
54         EXIT;
55 }
56
57 struct dentry *dotsnap_lookup(struct inode *dir,  struct dentry *dentry)
58 {
59         struct snap_table       *table;
60         struct snap_cache       *cache;
61         int i;
62         int index;
63         int tableno; 
64         ino_t ino;
65         struct inode *inode;
66         struct snapshot_operations *snapops;
67
68         ENTRY;
69
70         cache = snap_find_cache(dir->i_dev);
71         if ( !cache ) {
72                 CERROR("dotsnap_readdir: cannot find cache\n");
73                 make_bad_inode(dir);
74                 RETURN(ERR_PTR(-EINVAL));
75         }
76
77         snapops = filter_c2csnapops(cache->cache_filter);
78         if (!snapops || !snapops->get_indirect_ino) {
79                 RETURN(ERR_PTR(-EINVAL));
80         }
81
82         tableno = cache->cache_snap_tableno; 
83         table = &snap_tables[tableno];
84
85         if( table->tbl_count <= 1 )
86                 RETURN(NULL);
87         
88         index = table->snap_items[0].index;; 
89         for ( i = 1 ; i < table->tbl_count ; i++ ) {
90                 if ( (dentry->d_name.len == strlen(table->snap_items[i].name)) &&
91                      (memcmp(&dentry->d_name.name[0], &table->snap_items[i].name[0], 
92                              dentry->d_name.len) == 0) ) {
93                         index = table->snap_items[i].index; 
94                         break;
95                 }
96         }
97         
98         if( i >= table->tbl_count )
99                 RETURN(ERR_PTR(-ENOENT));
100
101         inode = iget(dir->i_sb, dir->i_ino & (~0xF0000000));
102
103         if ( !inode ) 
104                 RETURN(ERR_PTR(-EINVAL));
105
106         ino =  snapops->get_indirect_ino(inode, index);
107         iput(inode); 
108
109         if ( ino == -ENOATTR || ino == 0 ) {
110                 ino = dir->i_ino & (~0xF0000000);
111         }
112
113         if ( ino == -EINVAL ) {
114                 RETURN(ERR_PTR(-EINVAL));
115         }
116         CDEBUG(D_INODE, "index %d, ino is %lu\n",index, ino);
117
118         inode = iget(dir->i_sb, ino);
119         d_add(dentry, inode); 
120         dentry->d_fsdata = (void*)index;
121         inode->i_op = dentry->d_parent->d_parent->d_inode->i_op;
122         RETURN(NULL);
123 }
124
125
126 static int dotsnap_readdir(struct file * filp,
127                            void * dirent, filldir_t filldir)
128 {
129         unsigned int i;
130         int tableno;
131         struct snap_cache *cache;
132         struct snap_table *table; 
133         struct snapshot_operations *snapops;
134
135         ENTRY; 
136
137         cache = snap_find_cache(filp->f_dentry->d_inode->i_dev);
138         if ( !cache ) {
139                 CDEBUG(D_INODE, "dotsnap_readdir: cannot find cache\n");
140                 make_bad_inode(filp->f_dentry->d_inode);
141                 RETURN(-EINVAL);
142         }
143
144         snapops = filter_c2csnapops(cache->cache_filter);
145         if (!snapops || !snapops->get_indirect_ino) {
146                 RETURN(-EINVAL);
147         }
148
149         tableno = cache->cache_snap_tableno; 
150         table = &snap_tables[tableno];
151         for (i = filp->f_pos ; i < table->tbl_count -1 ; i++) {
152                 int index;
153                 struct inode *inode;
154                 ino_t ino;
155
156
157                 inode = filp->f_dentry->d_inode;
158                 index = table->snap_items[i+1].index;
159                 ino =  snapops->get_indirect_ino 
160                         (filp->f_dentry->d_inode, index);
161
162                 if ( ino == -ENOATTR || ino == 0 ) {
163                         ino = filp->f_dentry->d_parent->d_inode->i_ino;
164                 }
165                 
166                 if ( ino == -EINVAL ) {
167                         return -EINVAL;
168                 }
169
170                 CDEBUG(D_INODE, "Listing %s\n", &table->snap_items[i+1].name[0]);       
171                 if (filldir(dirent, &table->snap_items[i+1].name[0],
172                             strlen(&table->snap_items[i+1].name[0]),
173                             filp->f_pos, ino, 0) < 0){
174                         CDEBUG(D_INODE, "\n");
175                         break;
176                 }
177                 filp->f_pos++;
178         }
179         RETURN(0);
180 }
181
182
183 struct file_operations dotsnap_file_operations = {
184         readdir: dotsnap_readdir,        /* readdir */
185 };
186
187 struct inode_operations dotsnap_inode_operations =
188 {
189         lookup: dotsnap_lookup
190 };