http://prdownloads.sourceforge.net/lufs/lufs-0.9.6.tar.gz?download
[lufs.git] / kernel / Linux / 2.4 / inode.c
1 /*
2  * inode.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/init.h>
27 #include <linux/fs.h>
28 #include <linux/slab.h>
29 #include <linux/list.h>
30 #include <linux/smp_lock.h>
31 #include <linux/signal.h>
32 #include <linux/sched.h>
33
34 #include <asm/system.h>
35 #include <asm/uaccess.h>
36
37 #include "lufs.h"
38 #include "proc.h"
39
40 MODULE_AUTHOR("Florin Malita <mali@go.ro>");
41 MODULE_DESCRIPTION("Linux Userland Filesystem");
42 #ifdef MODULE_LICENSE
43 MODULE_LICENSE("GPL");
44 #endif
45
46 extern struct file_operations lu_dir_operations, lu_file_operations;
47 extern struct inode_operations lu_dir_inode_operations, lu_file_inode_operations, lu_symlink_inode_operations;
48 extern struct address_space_operations lu_file_aops;
49 extern struct dentry_operations lufs_dentry_operations;
50
51 static void lu_delete_inode(struct inode*);
52 static void lu_put_super(struct super_block*);
53 static int  lu_statfs(struct super_block*, struct statfs*);
54
55 static struct super_operations lu_sops = {
56     put_inode:          force_delete,
57     delete_inode:       lu_delete_inode,
58     put_super:          lu_put_super,
59     statfs:             lu_statfs,
60 };
61
62 static void parse_options(struct lufs_sb_info *server, char *opts)
63 {
64     char *p, *q;
65     int len, i;
66
67     if(!opts)
68         return;
69
70     len = strlen(opts);
71
72     for(p = strtok(opts, ","); p; p = strtok(NULL, ",")){
73         if(strncmp(p, "server_socket=", 14) == 0){
74             if(strlen(p+14) > UNIX_PATH_MAX)
75                 goto ugly_opts;
76             strcpy(server->server_socket, p+14);
77             TRACE("server_socket: %s\n", server->server_socket);
78         }else 
79         if(strncmp(p, "uid=", 4) == 0){
80             if(current->uid)
81                 ERROR("only root can use uid option!\n");
82             else{
83                 if(strlen(p+4) > 5)
84                     goto ugly_opts;
85                 q = p + 4;
86                 server->config.uid = simple_strtoul(q, &q, 0);
87                 TRACE("uid: %d\n", server->config.uid); 
88             }
89         }else
90         if(strncmp(p, "gid=", 4) == 0){
91             if(current->uid)
92                 ERROR("only root can use gid option!\n");
93             else{
94                 if(strlen(p+4) > 5)
95                     goto ugly_opts;
96                 q = p + 4;
97                 server->config.gid = simple_strtoul(q, &q, 0);
98                 TRACE("gid: %d\n", server->config.gid); 
99             }
100         }else
101         if(strncmp(p, "fmask=", 6) == 0){
102             if(strlen(p + 6) > 3)
103                 goto ugly_opts;
104             q = p + 6;
105             server->config.fmode = (((q[0] - '0') << 6) + ((q[1] - '0') << 3) + (q[2] - '0')) & (S_IRWXU | S_IRWXG | S_IRWXO);
106             TRACE("fmode: %d\n", server->config.fmode);
107         }else
108         if(strncmp(p, "dmask=", 6) == 0){
109             if(strlen(p + 6) > 3)
110                 goto ugly_opts;
111             q = p + 6;
112             server->config.dmode = (((q[0] - '0') << 6) + ((q[1] - '0') << 3) + (q[2] - '0')) & (S_IRWXU | S_IRWXG | S_IRWXO);
113             TRACE("dmode: %d\n", server->config.dmode);
114         }else
115         if(strncmp(p, "root=", 5) == 0){
116             if(strlen(p+5) >= UNIX_PATH_MAX - 1)
117                 goto ugly_opts;
118             strcpy(server->root, p+5);
119             server->rootlen = strlen(server->root);
120             
121             if(server->root[server->rootlen - 1] == '/'){
122                 server->root[server->rootlen - 1] = 0;
123                 server->rootlen--;
124             }
125                             
126             TRACE("remote root: %s, len: %u\n", server->root, server->rootlen);
127         }else
128         if(strncmp(p, "channels=", 9) == 0){
129             if(strlen(p+9) > 5)
130                 goto ugly_opts;
131             q = p + 9;
132             server->config.channels = simple_strtoul(q, &q, 0);
133             
134             TRACE("channels: %u\n", server->config.channels);
135         }else
136         if(strncmp(p, "own_fs", 6) == 0){
137             server->config.own_fs = 1;
138             TRACE("forcing ownership\n");
139         }else
140         if(strncmp(p, "server_pid=", 11) == 0){
141             if(strlen(p+11) > 7)
142                 goto ugly_opts;
143             q = p + 11;
144             server->server_pid = simple_strtoul(q, &q, 0);
145
146             TRACE("server_pid: %u\n", server->server_pid);
147         }
148            
149     }
150
151     for(i = 0; i < len; i++)
152         if(!opts[i])
153             opts[i] = ',';
154
155     return;
156
157   ugly_opts:
158     WARN("evil options!\n");
159 }
160
161 static void set_inode_attr(struct inode *inode, struct lufs_fattr *fattr)
162 {
163     time_t last_time = inode->i_mtime;
164     loff_t last_sz = inode->i_size;
165
166     TRACE("in\n");
167     
168     inode->i_mode = fattr->f_mode;
169     inode->i_nlink = fattr->f_nlink;
170     inode->i_uid = fattr->f_uid;
171     inode->i_gid = fattr->f_gid;
172     inode->i_ctime = fattr->f_ctime;
173     inode->i_mtime = fattr->f_mtime;
174     inode->i_atime = fattr->f_atime;
175     inode->i_blksize = fattr->f_blksize;
176     inode->i_blocks = fattr->f_blocks;
177     inode->i_size = fattr->f_size;
178
179     inode->i_rdev = 0;
180
181     if(inode->i_mtime != last_time || inode->i_size != last_sz){
182         TRACE("inode changed...\n");
183         if(!S_ISDIR(inode->i_mode))
184             invalidate_inode_pages(inode);
185     }
186
187     TRACE("out\n");
188 }
189
190 static int lu_do_stat(struct dentry *dentry, struct lufs_fattr *fattr)
191 {
192     struct server_slot *slot;
193     struct iovec siov, riov;
194     int res;
195
196     TRACE("in\n");
197
198     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
199         return -ERESTARTSYS;
200
201     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
202         WARN("lu_getname failed!\n");
203         goto out;
204     }
205
206     TRACE("stating %s...\n", slot->s_buf);
207
208     siov.iov_base = slot->s_buf;
209     siov.iov_len = strlen(slot->s_buf) + 1;
210     riov.iov_base = fattr;
211     riov.iov_len = sizeof(struct lufs_fattr);
212
213     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0)
214         goto out;
215
216     if(PIS_ERROR(res)){
217         WARN("stat failed!\n");
218         res = PERROR(res);
219         goto out;
220     }
221
222     lu_fixattrs(GET_INFO(dentry->d_sb), fattr);
223
224     res = 0;
225
226   out:
227     TRACE("out\n");
228     lu_putslot(slot);
229     return res;
230 }
231
232 static int lu_refresh_inode(struct dentry *dentry)
233 {
234     struct inode *inode = dentry->d_inode;
235     struct lufs_fattr fattr;
236     int res;
237
238     TRACE("in\n");
239
240     if((res = lu_do_stat(dentry, &fattr)) < 0)
241         return res;
242
243     dentry->d_time = jiffies;
244
245     if(!inode)
246         return 0;
247
248     if((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT))
249         set_inode_attr(inode, &fattr);
250     else{
251         WARN("inode changed mode, %x to %x\n", inode->i_mode, (unsigned int)fattr.f_mode);
252         TRACE("oops!\n");
253         
254         fattr.f_mode = inode->i_mode;
255         make_bad_inode(inode);
256         inode->i_mode = fattr.f_mode;
257
258         if(!S_ISDIR(inode->i_mode))
259             invalidate_inode_pages(inode);
260         
261         return -EIO;
262     }
263
264     TRACE("out\n");
265     return 0;
266 }
267
268 int lu_revalidate_inode(struct dentry *dentry)
269 {
270     int res = 0;
271
272     TRACE("in\n");
273
274     lock_kernel();
275     
276     if(time_before(jiffies, dentry->d_time + LU_MAXAGE)){
277         TRACE("up-to-date, age=%lu\n", jiffies - dentry->d_time);
278         goto out;
279     }
280
281     res = lu_refresh_inode(dentry);
282
283   out:
284     unlock_kernel();
285     return res;
286 }
287
288 int lufs_notify_change(struct dentry *dentry, struct iattr *iattr)
289 {
290     struct server_slot *slot;
291     struct iovec iov[2];
292     struct lufs_fattr fattr;
293     int res;
294
295     TRACE("in\n");
296
297     if((res = lu_do_stat(dentry, &fattr)) < 0)
298         return res;
299
300     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
301         return -ERESTARTSYS;
302
303     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
304         WARN("lu_getname failed!\n");
305         goto out;
306     }
307     
308     if(iattr->ia_valid & ATTR_MODE)
309         fattr.f_mode = iattr->ia_mode;
310     if(iattr->ia_valid & ATTR_UID)
311         fattr.f_uid  = iattr->ia_uid;
312     if(iattr->ia_valid & ATTR_GID)
313         fattr.f_gid  = iattr->ia_gid;
314     if(iattr->ia_valid & ATTR_SIZE)
315         fattr.f_size = iattr->ia_size;
316     if(iattr->ia_valid & ATTR_ATIME)
317         fattr.f_atime= iattr->ia_atime;
318     if(iattr->ia_valid & ATTR_MTIME)
319         fattr.f_mtime= iattr->ia_mtime;
320     if(iattr->ia_valid & ATTR_CTIME)
321         fattr.f_ctime= iattr->ia_ctime;
322
323     iov[0].iov_base = &fattr;
324     iov[0].iov_len = sizeof(struct lufs_fattr);
325     iov[1].iov_base = slot->s_buf;
326     iov[1].iov_len = strlen(slot->s_buf) + 1;
327
328     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_SETATTR, iov, 2, NULL, 0)) < 0)
329         goto out;
330
331     if(PIS_ERROR(res)){
332         WARN("setattr failed!\n");
333         res = PERROR(res);
334         goto out;
335     }
336
337     res = 0;
338
339     lu_refresh_inode(dentry);
340
341   out:
342     TRACE("out\n");
343     lu_putslot(slot);
344     return res;
345 }
346
347
348 struct inode* lu_iget(struct super_block *sb, struct lufs_fattr *fattr)
349 {
350     struct inode *res;
351
352     TRACE("in\n");
353     
354     res = new_inode(sb);
355     if(!res)
356         return NULL;
357     res->i_ino = fattr->f_ino;
358     set_inode_attr(res, fattr);
359
360     if(S_ISDIR(res->i_mode)){
361         TRACE("it's a dir.\n");
362         res->i_op = &lu_dir_inode_operations;
363         res->i_fop = &lu_dir_operations;
364     }else if(S_ISLNK(res->i_mode)){
365         TRACE("it's a link.\n");
366         res->i_op = &lu_symlink_inode_operations;
367     }else{
368         TRACE("it's a file.\n");
369         res->i_op = &lu_file_inode_operations;
370         res->i_fop = &lu_file_operations;
371         res->i_data.a_ops = &lu_file_aops;
372     }
373         
374     insert_inode_hash(res);
375     return res;
376 }
377  
378 static int lu_statfs(struct super_block *sb, struct statfs *attr)
379 {
380     TRACE("in\n");
381     
382     attr->f_type = LU_MAGIC;
383     attr->f_bsize = LU_BLOCKSIZE;
384     attr->f_blocks = 0;
385     attr->f_namelen = LU_MAXPATHLEN;
386     attr->f_files = -1;
387     attr->f_bavail = -1;
388
389     TRACE("out\n");
390     return 0;
391 }
392
393 static void lu_put_super(struct super_block *sb)
394 {
395     struct siginfo info;
396
397     TRACE("in\n");
398
399     info.si_signo = SIGUSR1;
400     info.si_errno = 0;
401     info.si_code = SI_USER;
402     info.si_pid = current->pid;
403     info.si_uid = current->uid;
404     
405     kill_proc_info(SIGUSR1, &info, GET_INFO(sb)->server_pid);
406
407     lu_empty_slots(GET_INFO(sb));
408     kfree(GET_INFO(sb));
409     TRACE("out\n");
410 }
411
412 static void lu_delete_inode(struct inode *in)
413 {
414     TRACE("in\n");
415     clear_inode(in);
416     TRACE("out\n");
417 }
418
419 static struct super_block* lu_read_super(struct super_block *sb, void *opts, int silent)
420 {
421     struct lufs_sb_info *info;
422     struct server_slot *slot;
423     struct lufs_fattr root_attr;
424     struct inode *root_inode;
425
426     int i;
427
428     TRACE("in\n");
429     
430     if(!opts){
431         ERROR("need some options here!\n");
432         goto out;
433     }
434     
435     if((info = (struct lufs_sb_info*)kmalloc(sizeof(struct lufs_sb_info), GFP_KERNEL)) == NULL){
436         ERROR("kmalloc error!\n");
437         goto out;
438     }
439     memset(info, 0, sizeof(struct lufs_sb_info));
440     info->lock = RW_LOCK_UNLOCKED;
441     INIT_LIST_HEAD(&info->slots);
442
443     info->config.uid = current->uid;
444     info->config.gid = current->gid;    
445     info->config.channels = LU_NRSLOTS;
446     
447     parse_options(info, opts);
448     
449     if(!info->server_socket[0]){
450         ERROR("no server_socket specified!\n");
451         goto out_info;
452     }
453     
454     for(i = 0; i < info->config.channels; i++){
455         if((slot = kmalloc(sizeof(struct server_slot), GFP_KERNEL)) == NULL){
456             ERROR("kmalloc error!\n");
457             goto out_slots;
458         }
459         memset(slot, 0, sizeof(struct server_slot));
460         init_MUTEX(&slot->s_lock);
461         if((slot->s_buf = kmalloc(LU_MAXDATA, GFP_KERNEL)) == NULL){
462             ERROR("kmalloc error!\n");
463             goto out_slots;
464         }
465         list_add(&slot->s_list, &info->slots);
466     }
467
468     sb->u.generic_sbp = info;
469     sb->s_blocksize = LU_BLOCKSIZE;
470     sb->s_blocksize_bits = LU_BLOCKSIZEBITS;
471     sb->s_magic = LU_MAGIC;
472     sb->s_op = &lu_sops;
473     sb->s_flags = 0;
474     sb->s_maxbytes = ((((unsigned long long)1) << 32) << LU_BLOCKSIZEBITS) - 1;
475
476     TRACE("sb->s_maxbytes=%Ld\n",sb->s_maxbytes);
477
478     lu_lookup_root(info, &root_attr);
479     root_inode = lu_iget(sb, &root_attr);
480     if(!root_inode)
481         goto out_slots;
482     sb->s_root = d_alloc_root(root_inode);
483     if(!sb->s_root)
484         goto out_slots;
485
486     sb->s_root->d_op = &lufs_dentry_operations;
487     sb->s_root->d_time = jiffies;
488
489     TRACE("mount succeded: %s\n", info->server_socket);
490     return sb;
491
492  out_slots:
493     lu_empty_slots(info);
494  out_info:
495     kfree(info);
496  out:
497     ERROR("mount failed!\n");
498     return NULL;
499 }
500
501 static DECLARE_FSTYPE(lu_fs_type, "lufs", lu_read_super, 0);
502
503 static int __init lu_init(void)
504 {
505     EXPORT_NO_SYMBOLS;
506
507     VERBOSE("UserLand File System\n");
508     VERBOSE("Copyright (c) 2002, Florin Malita\n");
509     return register_filesystem(&lu_fs_type);
510 }
511
512 static void __exit lu_release(void)
513 {
514     VERBOSE("Unregistering lufs...\n");
515     unregister_filesystem(&lu_fs_type);
516 }
517
518 module_init(lu_init);
519 module_exit(lu_release);