http://prdownloads.sourceforge.net/lufs/lufs-0.9.6.tar.gz?download
[lufs.git] / kernel / Linux / 2.4 / file.c
1 /*
2  * file.c
3  * Copyright (C) 2002 Florin Malita <mali@go.ro>
4  *
5  * This file is part of LUFS, a free userspace filesystem implementation.
6  * See http://lufs.sourceforge.net/ for updates.
7  *
8  * LUFS is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * LUFS is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <linux/version.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/pagemap.h>
28
29 #include <asm/uaccess.h>
30 #include <asm/system.h>
31
32 #include <linux/smp_lock.h>
33
34 #include "lufs.h"
35 #include "proc.h"
36
37 extern int lufs_notify_change(struct dentry*, struct iattr*);
38 extern int lu_revalidate_inode(struct dentry*);
39
40 static int lu_file_open(struct inode *inode, struct file *file)
41 {
42     int res, gres;
43     struct server_slot *slot;
44     struct iovec iov[2];
45     unsigned flags;
46
47     TRACE("in\n");
48
49     if((gres = generic_file_open(inode, file)) < 0)
50         return gres;
51
52     TRACE("f_mode: %u, i_mode: %u\n", file->f_mode, inode->i_mode);
53     TRACE("f_flags: %u, i_flags: %u\n", file->f_flags, inode->i_flags);
54
55     if((slot = lu_getslot(GET_INFO(file->f_dentry->d_sb))) == NULL)
56         return gres;
57
58     if((res = lu_getname(file->f_dentry, slot->s_buf, LU_MAXDATA)) < 0){
59         WARN("lu_getname failed!\n");
60         goto out;
61     }
62
63     flags = file->f_flags & O_ACCMODE;
64     iov[0].iov_base = &flags;
65     iov[0].iov_len = sizeof(flags);
66     iov[1].iov_base = slot->s_buf;
67     iov[1].iov_len = strlen(slot->s_buf) + 1;
68
69     lu_execute(GET_INFO(file->f_dentry->d_sb), slot, PTYPE_OPEN, iov, 2, NULL, 0);
70
71 out:
72     lu_putslot(slot);
73
74     TRACE("out\n");
75     return gres;
76 }
77
78 static int lu_file_release(struct inode *inode, struct file *file)
79 {
80     int res;
81     struct server_slot *slot;
82     struct iovec iov;
83
84     TRACE("in\n");
85
86     if((slot = lu_getslot(GET_INFO(file->f_dentry->d_sb))) == NULL)
87         return -ERESTARTSYS;
88
89     if((res = lu_getname(file->f_dentry, slot->s_buf, LU_MAXPATHLEN)) < 0){
90         WARN("lu_getname failed!\n");
91         goto out;
92     }
93     
94     iov.iov_base = slot->s_buf;
95     iov.iov_len = strlen(slot->s_buf) + 1;
96
97     if((res = lu_execute(GET_INFO(file->f_dentry->d_sb), slot, PTYPE_RELEASE, &iov, 1, NULL, 0)) < 0)
98         goto out;
99
100     if(PIS_ERROR(res)){
101         TRACE("release failed\n");
102         res = PERROR(res);
103         goto out;
104     }
105     
106     res = 0;
107
108 out:
109     lu_putslot(slot);
110
111     TRACE("out\n");
112     return res;
113 }
114
115 static int lu_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
116 {
117     struct dentry *dentry = filp->f_dentry;
118     int res;
119
120     TRACE("in\n");
121
122     if(!(res = lu_revalidate_inode(dentry)))
123         res = generic_file_read(filp, buf, count, ppos);
124
125     TRACE("out\n");
126     
127     return res;
128 }
129
130 static int lu_file_readpage(struct file *f, struct page *p)
131 {
132     int res;
133     struct iovec siov[3], riov;
134     long long offset;
135     unsigned long count;
136     struct server_slot *slot;
137
138     TRACE("in\n");
139
140     if((slot = lu_getslot(GET_INFO(f->f_dentry->d_sb))) == NULL)
141         return -ERESTARTSYS;
142
143     get_page(p);
144
145     if((res = lu_getname(f->f_dentry, slot->s_buf, LU_MAXDATA)) < 0){
146         WARN("lu_getname failed!\n");
147         goto out;
148     }
149
150     offset = p->index << PAGE_CACHE_SHIFT;
151     count = PAGE_SIZE;
152
153     siov[0].iov_base = &offset;
154     siov[0].iov_len = sizeof(offset);
155     siov[1].iov_base = &count;
156     siov[1].iov_len = sizeof(count);
157     siov[2].iov_base = slot->s_buf;
158     siov[2].iov_len = strlen(slot->s_buf) + 1;
159
160     riov.iov_base = page_address(p);
161     riov.iov_len = count;
162
163     if((res = lu_execute(GET_INFO(f->f_dentry->d_sb), slot, PTYPE_READ, siov, 3, &riov, 1)) < 0)
164         goto out;
165
166     if(PIS_ERROR(res)){
167         TRACE("read failed\n");
168         res = PERROR(res);
169         goto out;
170     }
171     
172     flush_dcache_page(p);
173     SetPageUptodate(p);
174     res = 0;
175     
176   out:
177     lu_putslot(slot);
178     UnlockPage(p);
179     put_page(p);
180         
181     TRACE("out\n");
182     return res;
183 }
184
185 static int lu_file_writepage(struct page *p)
186 {
187     TRACE("in\n");
188
189     TRACE("out\n");
190     return -1;
191 }
192
193 static int lu_file_preparewrite(struct file *f, struct page *p, unsigned offset, unsigned to)
194 {
195     TRACE("in\n");
196
197     TRACE("out\n");
198
199     return 0;
200 }
201
202 static int lu_file_commitwrite(struct file *f, struct page *p, unsigned offset, unsigned to)
203 {
204     int res;
205     struct server_slot *slot;
206     struct iovec iov[4];
207     char *buf;
208     long long off;
209     unsigned long cnt;
210
211     TRACE("in\n");
212
213     if((slot = lu_getslot(GET_INFO(f->f_dentry->d_sb))) == NULL)
214         return -ERESTARTSYS;
215
216     if((res = lu_getname(f->f_dentry, slot->s_buf, LU_MAXDATA)) < 0){
217         WARN("lu_getname failed!\n");
218         goto out2;
219     }
220
221     lock_kernel();
222
223     buf = kmap(p) + offset;
224     cnt = to - offset;
225     off = offset + (((long long)p->index) << PAGE_CACHE_SHIFT);
226
227     iov[0].iov_base = &off;
228     iov[0].iov_len = sizeof(off);
229     iov[1].iov_base = &cnt;
230     iov[1].iov_len = sizeof(cnt);
231     iov[2].iov_base = slot->s_buf;
232     iov[2].iov_len = strlen(slot->s_buf) + 1;
233     iov[3].iov_base = buf;
234     iov[3].iov_len = cnt;
235
236     TRACE("write %s, offset %Ld, count %d\n", slot->s_buf, off, (int)cnt);
237
238     if((res = lu_execute(GET_INFO(f->f_dentry->d_sb), slot, PTYPE_WRITE, iov, 4, NULL, 0)) < 0)
239         goto out1;
240
241
242     if(PIS_ERROR(res)){
243         TRACE("write failed\n");
244         res = PERROR(res);
245         goto out1;
246     }
247
248     f->f_dentry->d_inode->i_mtime = f->f_dentry->d_inode->i_atime = CURRENT_TIME;
249     if(off + cnt > f->f_dentry->d_inode->i_size)
250         f->f_dentry->d_inode->i_size = off + cnt;
251
252     res = cnt;
253
254   out1:
255     kunmap(p);
256     unlock_kernel();
257   out2:
258     lu_putslot(slot);
259     TRACE("out\n");
260     return res;
261 }
262
263 static int lu_file_mmap(struct file *filp, struct vm_area_struct *vma)
264 {
265     struct dentry *dentry = filp->f_dentry;
266     int res;
267
268     TRACE("in\n");
269
270     if(!(res = lu_revalidate_inode(dentry)))
271         res = generic_file_mmap(filp, vma);
272
273     TRACE("out\n");
274
275     return res;
276 }
277
278 static ssize_t lu_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
279 {
280     struct dentry *dentry = filp->f_dentry;
281     ssize_t res;
282
283     TRACE("in\n");
284
285     if(!(res = lu_revalidate_inode(dentry)) && (count > 0))
286         res = generic_file_write(filp, buf, count, ppos);
287
288     TRACE("out\n");
289
290     return res;
291 }
292
293 /*
294  *  Without this function, fsync() returns EINVAL indicating that the
295  *  file is special (eg pipe or socket) and does not support
296  *  synchronization.
297  *
298  *  This causes, for example, Emacs to report "Writing file: Invalid
299  *  argument, <filename>" when saving a file to a lufs file system.
300  *
301  *  The opengroup spec states "It is explicitly intended that a null
302  *  implementation is permitted." This is therefore a quick but valid
303  *  hack to avoid this problem.
304  *
305  *  See http://www.moses.uklinux.net/patches/lki-3.html#ss3.4
306  *      http://www.opengroup.org/onlinepubs/007904975/functions/fsync.html
307  * 
308  *  James Marsh <marshj@cs.man.ac.uk> 22-Apr-2003 
309  */
310 static int lu_file_fsync(struct file *filp, struct dentry *dentryp, int datasync)
311 {    
312     return 0;
313 }
314
315 struct file_operations lu_file_operations = {
316     llseek:     generic_file_llseek,
317     read:       lu_file_read,
318     write:      lu_file_write,
319     mmap:       lu_file_mmap,
320     open:       lu_file_open,
321     release:    lu_file_release,
322     fsync:      lu_file_fsync
323 };
324
325 struct inode_operations lu_file_inode_operations = {
326     revalidate: lu_revalidate_inode,
327     setattr:    lufs_notify_change,
328 };
329
330 struct address_space_operations lu_file_aops = {
331     readpage:           lu_file_readpage,
332     writepage:          lu_file_writepage,
333     prepare_write:      lu_file_preparewrite,
334     commit_write:       lu_file_commitwrite,
335 };
336
337
338