Whamcloud - gitweb
remove unecessary debugging
[fs/lustre-release.git] / lustre / snapfs / file.c
1 /*
2  * file.c
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/pagemap.h>
14 #include <linux/jbd.h>
15 #include <linux/ext3_fs.h>
16 #include <linux/snap.h>
17
18 #include "snapfs_internal.h" 
19
20 static int has_pages(struct inode *inode, int index)
21 {
22         unsigned long offset = index << PAGE_CACHE_SHIFT;
23         unsigned long blk_start = offset >> inode->i_sb->s_blocksize_bits; 
24         unsigned long blk_end = (offset + PAGE_CACHE_SIZE) >> 
25                                 inode->i_sb->s_blocksize_bits; 
26
27         while (blk_start <= blk_end) {
28                 if (inode->i_mapping && inode->i_mapping->a_ops) {
29                         if (inode->i_mapping->a_ops->bmap(inode->i_mapping, 
30                                                           blk_start))
31                                 return 1;
32                 }
33                 blk_start++;
34         }
35         return 0;
36 }
37
38 static int copy_back_page(struct inode *dst, 
39                           struct inode *src,
40                           unsigned long start,
41                           unsigned long end)
42 {
43         char *kaddr_src, *kaddr_dst;
44         struct snap_cache *cache;
45         struct address_space_operations *c_aops;
46         struct page *src_page = NULL, *dst_page = NULL;
47         unsigned long index, offset, bytes;
48         int    err = 0;
49         ENTRY;
50
51         offset = (start & (PAGE_CACHE_SIZE -1)); /* Within page */
52         bytes = end - start;
53         index = start >> PAGE_CACHE_SHIFT;
54
55         if (!has_pages(src, index) || bytes > 4096) 
56                 RETURN(0);
57
58         cache = snap_find_cache(src->i_dev);
59         if (!cache) 
60                 RETURN(-EINVAL);
61         c_aops = filter_c2cfaops(cache->cache_filter);
62         
63         if (!c_aops) 
64                 RETURN(-EINVAL);
65
66         src_page = grab_cache_page(src->i_mapping, index);
67         if (!src_page) {
68                 CERROR("copy block %lu from %lu to %lu ENOMEM \n",
69                           index, src->i_ino, dst->i_ino);
70                 RETURN(-ENOMEM);
71         }
72         
73         c_aops->readpage(NULL, src_page);
74         wait_on_page(src_page);
75         
76         kaddr_src = kmap(src_page);
77         if (!Page_Uptodate(src_page)) {
78                 CERROR("Can not read page index %lu of inode %lu\n",
79                           index, src->i_ino);
80                 err = -EIO;
81                 goto unlock_src_page;
82         }
83         dst_page = grab_cache_page(dst->i_mapping, index);
84         if (!dst_page) {
85                 CERROR("copy block %lu from %lu to %lu ENOMEM \n",
86                           index, src->i_ino, dst->i_ino);
87                 err = -ENOMEM;
88                 goto unlock_src_page;
89         }       
90         kaddr_dst = kmap(dst_page);
91
92         err = c_aops->prepare_write(NULL, dst_page, offset, offset + bytes);
93         if (err) 
94                 goto unlock_dst_page; 
95         memcpy(kaddr_dst, kaddr_src, PAGE_CACHE_SIZE);
96         flush_dcache_page(dst_page);
97
98         err = c_aops->commit_write(NULL, dst_page, offset, offset + bytes);
99         CDEBUG(D_SNAP, "copy back pages %p index %lu src %lu dst %lu \n",
100                dst_page, dst_page->index, src->i_ino, dst->i_ino); 
101         if (err) 
102                 goto unlock_dst_page; 
103         err = 1;
104 unlock_dst_page:
105         kunmap(dst_page);
106         UnlockPage(dst_page);
107         page_cache_release(dst_page);
108 unlock_src_page:
109         kunmap(src_page);
110         page_cache_release(src_page);
111         RETURN(err);
112 }
113
114 static ssize_t currentfs_write (struct file *filp, const char *buf, 
115                                 size_t count, loff_t *ppos)
116 {
117         struct snap_cache *cache;
118         struct inode *inode = filp->f_dentry->d_inode;
119         struct file_operations *fops;
120         long   start[2]={-1,-1}, end[2]={-1,-1};
121         struct snap_table *table;
122         struct inode *cache_inode = NULL;
123         int slot = 0, index = 0, result = 0;
124         long i;
125         ssize_t rc;
126         loff_t pos;
127   
128         ENTRY;
129
130         if (currentfs_is_under_dotsnap(filp->f_dentry)) 
131                 RETURN(-ENOSPC);
132
133         cache = snap_find_cache(inode->i_dev);
134         if ( !cache ) 
135                 RETURN(-EINVAL);
136
137         down(&inode->i_sem);
138
139         if ( snap_needs_cow(inode) != -1 ) {
140                 CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
141                 snap_do_cow(inode, filp->f_dentry->d_parent->d_inode->i_ino, 0);
142         }
143
144         fops = filter_c2cffops(cache->cache_filter); 
145         if (!fops || !fops->write) { 
146                 up(&inode->i_sem); 
147                 RETURN(-EINVAL);
148         }
149         if (filp->f_flags & O_APPEND)
150                 pos = inode->i_size;
151         else {
152                 pos = *ppos;
153                 if (pos != *ppos){
154                         up(&inode->i_sem); 
155                         RETURN(-EINVAL);
156                 }
157         }
158         
159         CDEBUG(D_SNAP, "write offset %lld count %u \n", pos, count);
160         
161         if (pos & (PAGE_CACHE_SIZE - 1)) {
162                 start[0] = pos & PAGE_CACHE_MASK;
163                 end[0] = pos;
164         }
165         pos += count - 1;
166         if ((pos+1) & (PAGE_CACHE_SIZE - 1)) {
167                 start[1] = pos;  
168                 end[1] = PAGE_CACHE_ALIGN(pos);
169         }
170
171         if (((start[0] >> PAGE_CACHE_SHIFT) == (start[1] >> PAGE_CACHE_SHIFT)) ||
172             pos > inode->i_size) 
173                 start[1] = -1;
174
175         CDEBUG(D_SNAP, "copy back start[0] %ld end[0] %ld start[1] %ld end[1] %ld \n",
176                start[0], end[0], start[1], end[1]);     
177         for (i = 0; i < 2; i++) {
178                 if (start[i] == -1) 
179                         continue;
180                 table = &snap_tables[cache->cache_snap_tableno];
181                 /*Find the nearest page in snaptable and copy back it*/
182                 for (slot = table->tbl_count - 1; slot >= 1; slot--) {
183                         cache_inode = NULL;
184                         index = table->snap_items[slot].index;
185                         cache_inode = snap_get_indirect(inode, NULL, index);
186
187                         if (!cache_inode)  continue;
188
189                         CDEBUG(D_SNAP, "find cache_ino %lu\n", cache_inode->i_ino);
190                 
191                         result = copy_back_page(inode, cache_inode, start[i], end[i]);
192                         if (result == 1) {
193                                 CDEBUG(D_SNAP, "copy page%lu back from ind %lu to %lu\n", 
194                                        (start[i] >> PAGE_CACHE_SHIFT), 
195                                        cache_inode->i_ino, 
196                                        inode->i_ino);
197                                 iput(cache_inode);
198                                 result = 0;
199                                 break;
200                         }
201                         if (result < 0) {
202                                 iput(cache_inode);
203                                 rc = result;
204                                 up(&inode->i_sem);
205                                 goto exit;
206                         }
207                         iput(cache_inode);
208                 }
209         }
210         
211         up(&inode->i_sem); 
212         rc = fops->write(filp, buf, count, ppos);
213 exit:
214         RETURN(rc);
215 }
216
217 static int currentfs_readpage(struct file *file, struct page *page)
218 {
219         struct inode *inode = file->f_dentry->d_inode;
220         unsigned long ind_ino = inode->i_ino;
221         struct inode *pri_inode = NULL;
222         struct inode *cache_inode = NULL;
223         struct address_space_operations *c_aops;
224         struct snap_cache *cache;
225         struct snap_table *table;
226         struct page *cache_page = NULL;
227         int rc = 0, slot = 0, index = 0, search_older = 0;
228         long block;
229
230         ENTRY;
231
232         cache = snap_find_cache(inode->i_dev);
233         if ( !cache ) { 
234                 RETURN(-EINVAL);
235         }
236         
237         c_aops = filter_c2cfaops(cache->cache_filter);
238
239         block = (page->index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
240
241         /* if there is a block in the cache, return the cache readpage */
242         if(c_aops->bmap(inode->i_mapping, block) ) {
243                 CDEBUG(D_SNAP, "block %lu in cache, ino %lu\n", 
244                                 block, inode->i_ino);
245                 rc = c_aops->readpage(file, page);
246                 RETURN(rc);
247         }
248
249         /*
250          * clonefs_readpage will fill this with primary ino number
251          * we need it to follow the cloned chain of primary inode
252          */
253         if( file->f_dentry->d_fsdata ){
254                 pri_inode = iget(inode->i_sb, (unsigned long)file->f_dentry->d_fsdata);
255                 if( !pri_inode )
256                         RETURN(-EINVAL);
257                 inode = pri_inode;
258                 search_older = 1;
259         }
260
261         table = &snap_tables[cache->cache_snap_tableno];
262
263         for (slot = table->tbl_count - 1; slot >= 1; slot--) {
264                 index = table->snap_items[slot].index;
265                 cache_inode = snap_get_indirect(inode, NULL, index);
266
267                 if (!cache_inode )  continue;
268
269                 /* we only want slots between cache_inode to the oldest one */
270                 if(search_older && cache_inode->i_ino == ind_ino )
271                         search_older = 0;
272
273                 if (!search_older && c_aops->bmap(cache_inode->i_mapping, block)) 
274                         break;
275                 iput(cache_inode);
276                 cache_inode = NULL;
277         }
278         if (pri_inode) iput(pri_inode);
279
280         if (!cache_inode) {
281                 CDEBUG(D_SNAP, "block %lu is a hole of inode %lu \n", 
282                        block, inode->i_ino);
283                 memset(kmap(page), 0, PAGE_CACHE_SIZE);
284                 flush_dcache_page(page);
285                 GOTO(exit, rc = 0);
286         }
287         CDEBUG(D_INODE, "readpage ino %lu icount %d \n", cache_inode->i_ino, 
288                atomic_read(&cache_inode->i_count));
289         down(&cache_inode->i_sem);
290
291         /*Here we have changed a file to read,
292          *So we should rewrite generic file read here 
293          *FIXME later, the code is ugly
294          */
295         
296         cache_page = grab_cache_page(cache_inode->i_mapping, page->index);
297         if (!cache_page) 
298                 GOTO(exit_release, rc = -ENOMEM);
299         if ((rc = c_aops->readpage(file, cache_page)))
300                 GOTO(exit_release, 0);
301         
302         wait_on_page(cache_page);
303
304         if (!Page_Uptodate(cache_page))
305                 GOTO(exit_release, rc = -EIO);
306
307         memcpy(kmap(page), kmap(cache_page), PAGE_CACHE_SIZE);
308         flush_dcache_page(page);
309
310         kunmap(cache_page);
311         page_cache_release(cache_page);
312
313         up(&cache_inode->i_sem);
314         iput(cache_inode);
315 exit:   
316         kunmap(page);
317         SetPageUptodate(page);
318         UnlockPage(page);
319
320         RETURN(rc);
321
322 exit_release:
323         if (cache_page) 
324                 page_cache_release(cache_page);
325         up(&cache_inode->i_sem);
326         iput(cache_inode);
327         UnlockPage(page);
328         RETURN(rc);
329 }
330
331 struct address_space_operations currentfs_file_aops = {
332         readpage:       currentfs_readpage,
333 };
334                                                                                                                                                                                                      
335 struct file_operations currentfs_file_fops = {
336         write:          currentfs_write,
337 };
338                                                                                                                                                                                                      
339 struct inode_operations currentfs_file_iops = {
340         setattr:        currentfs_setattr,
341         setxattr:       currentfs_setxattr,
342         removexattr:    currentfs_removexattr,  
343 };
344