3 * Copyright (C) 2002 Florin Malita <mali@go.ro>
5 * This file is part of LUFS, a free userspace filesystem implementation.
6 * See http://lufs.sourceforge.net/ for updates.
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.
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.
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
23 #include <linux/version.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/init.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>
34 #include <asm/system.h>
35 #include <asm/uaccess.h>
40 MODULE_AUTHOR("Florin Malita <mali@go.ro>");
41 MODULE_DESCRIPTION("Linux Userland Filesystem");
43 MODULE_LICENSE("GPL");
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;
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*);
55 static struct super_operations lu_sops = {
56 put_inode: force_delete,
57 delete_inode: lu_delete_inode,
58 put_super: lu_put_super,
62 static void parse_options(struct lufs_sb_info *server, char *opts)
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)
76 strcpy(server->server_socket, p+14);
77 TRACE("server_socket: %s\n", server->server_socket);
79 if(strncmp(p, "uid=", 4) == 0){
81 ERROR("only root can use uid option!\n");
86 server->config.uid = simple_strtoul(q, &q, 0);
87 TRACE("uid: %d\n", server->config.uid);
90 if(strncmp(p, "gid=", 4) == 0){
92 ERROR("only root can use gid option!\n");
97 server->config.gid = simple_strtoul(q, &q, 0);
98 TRACE("gid: %d\n", server->config.gid);
101 if(strncmp(p, "fmask=", 6) == 0){
102 if(strlen(p + 6) > 3)
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);
108 if(strncmp(p, "dmask=", 6) == 0){
109 if(strlen(p + 6) > 3)
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);
115 if(strncmp(p, "root=", 5) == 0){
116 if(strlen(p+5) >= UNIX_PATH_MAX - 1)
118 strcpy(server->root, p+5);
119 server->rootlen = strlen(server->root);
121 if(server->root[server->rootlen - 1] == '/'){
122 server->root[server->rootlen - 1] = 0;
126 TRACE("remote root: %s, len: %u\n", server->root, server->rootlen);
128 if(strncmp(p, "channels=", 9) == 0){
132 server->config.channels = simple_strtoul(q, &q, 0);
134 TRACE("channels: %u\n", server->config.channels);
136 if(strncmp(p, "own_fs", 6) == 0){
137 server->config.own_fs = 1;
138 TRACE("forcing ownership\n");
140 if(strncmp(p, "server_pid=", 11) == 0){
144 server->server_pid = simple_strtoul(q, &q, 0);
146 TRACE("server_pid: %u\n", server->server_pid);
151 for(i = 0; i < len; i++)
158 WARN("evil options!\n");
161 static void set_inode_attr(struct inode *inode, struct lufs_fattr *fattr)
163 time_t last_time = inode->i_mtime;
164 loff_t last_sz = inode->i_size;
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;
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);
190 static int lu_do_stat(struct dentry *dentry, struct lufs_fattr *fattr)
192 struct server_slot *slot;
193 struct iovec siov, riov;
198 if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
201 if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
202 WARN("lu_getname failed!\n");
206 TRACE("stating %s...\n", slot->s_buf);
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);
213 if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_STAT, &siov, 1, &riov, 1)) < 0)
217 WARN("stat failed!\n");
222 lu_fixattrs(GET_INFO(dentry->d_sb), fattr);
232 static int lu_refresh_inode(struct dentry *dentry)
234 struct inode *inode = dentry->d_inode;
235 struct lufs_fattr fattr;
240 if((res = lu_do_stat(dentry, &fattr)) < 0)
243 dentry->d_time = jiffies;
248 if((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT))
249 set_inode_attr(inode, &fattr);
251 WARN("inode changed mode, %x to %x\n", inode->i_mode, (unsigned int)fattr.f_mode);
254 fattr.f_mode = inode->i_mode;
255 make_bad_inode(inode);
256 inode->i_mode = fattr.f_mode;
258 if(!S_ISDIR(inode->i_mode))
259 invalidate_inode_pages(inode);
268 int lu_revalidate_inode(struct dentry *dentry)
276 if(time_before(jiffies, dentry->d_time + LU_MAXAGE)){
277 TRACE("up-to-date, age=%lu\n", jiffies - dentry->d_time);
281 res = lu_refresh_inode(dentry);
288 int lufs_notify_change(struct dentry *dentry, struct iattr *iattr)
290 struct server_slot *slot;
292 struct lufs_fattr fattr;
297 if((res = lu_do_stat(dentry, &fattr)) < 0)
300 if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
303 if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
304 WARN("lu_getname failed!\n");
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;
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;
328 if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_SETATTR, iov, 2, NULL, 0)) < 0)
332 WARN("setattr failed!\n");
339 lu_refresh_inode(dentry);
348 struct inode* lu_iget(struct super_block *sb, struct lufs_fattr *fattr)
357 res->i_ino = fattr->f_ino;
358 set_inode_attr(res, fattr);
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;
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;
374 insert_inode_hash(res);
378 static int lu_statfs(struct super_block *sb, struct statfs *attr)
382 attr->f_type = LU_MAGIC;
383 attr->f_bsize = LU_BLOCKSIZE;
385 attr->f_namelen = LU_MAXPATHLEN;
393 static void lu_put_super(struct super_block *sb)
399 info.si_signo = SIGUSR1;
401 info.si_code = SI_USER;
402 info.si_pid = current->pid;
403 info.si_uid = current->uid;
405 kill_proc_info(SIGUSR1, &info, GET_INFO(sb)->server_pid);
407 lu_empty_slots(GET_INFO(sb));
412 static void lu_delete_inode(struct inode *in)
419 static struct super_block* lu_read_super(struct super_block *sb, void *opts, int silent)
421 struct lufs_sb_info *info;
422 struct server_slot *slot;
423 struct lufs_fattr root_attr;
424 struct inode *root_inode;
431 ERROR("need some options here!\n");
435 if((info = (struct lufs_sb_info*)kmalloc(sizeof(struct lufs_sb_info), GFP_KERNEL)) == NULL){
436 ERROR("kmalloc error!\n");
439 memset(info, 0, sizeof(struct lufs_sb_info));
440 info->lock = RW_LOCK_UNLOCKED;
441 INIT_LIST_HEAD(&info->slots);
443 info->config.uid = current->uid;
444 info->config.gid = current->gid;
445 info->config.channels = LU_NRSLOTS;
447 parse_options(info, opts);
449 if(!info->server_socket[0]){
450 ERROR("no server_socket specified!\n");
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");
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");
465 list_add(&slot->s_list, &info->slots);
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;
474 sb->s_maxbytes = ((((unsigned long long)1) << 32) << LU_BLOCKSIZEBITS) - 1;
476 TRACE("sb->s_maxbytes=%Ld\n",sb->s_maxbytes);
478 lu_lookup_root(info, &root_attr);
479 root_inode = lu_iget(sb, &root_attr);
482 sb->s_root = d_alloc_root(root_inode);
486 sb->s_root->d_op = &lufs_dentry_operations;
487 sb->s_root->d_time = jiffies;
489 TRACE("mount succeded: %s\n", info->server_socket);
493 lu_empty_slots(info);
497 ERROR("mount failed!\n");
501 static DECLARE_FSTYPE(lu_fs_type, "lufs", lu_read_super, 0);
503 static int __init lu_init(void)
507 VERBOSE("UserLand File System\n");
508 VERBOSE("Copyright (c) 2002, Florin Malita\n");
509 return register_filesystem(&lu_fs_type);
512 static void __exit lu_release(void)
514 VERBOSE("Unregistering lufs...\n");
515 unregister_filesystem(&lu_fs_type);
518 module_init(lu_init);
519 module_exit(lu_release);