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