blob: fd301a91012243e25fe2ab9a77db3a9bda9b6acd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 *
5 * Ported the filesystem routines to 2.5.
6 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
7 */
8
9#include <linux/stddef.h>
10#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/slab.h>
14#include <linux/pagemap.h>
15#include <linux/blkdev.h>
16#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/statfs.h>
18#include <linux/kdev_t.h>
19#include <asm/uaccess.h>
20#include "hostfs.h"
21#include "kern_util.h"
22#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "init.h"
24
25struct hostfs_inode_info {
26 char *host_filename;
27 int fd;
28 int mode;
29 struct inode vfs_inode;
30};
31
32static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
33{
34 return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
35}
36
Josef Sipek680b0da2006-12-08 02:37:05 -080037#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39int hostfs_d_delete(struct dentry *dentry)
40{
41 return(1);
42}
43
44struct dentry_operations hostfs_dentry_ops = {
45 .d_delete = hostfs_d_delete,
46};
47
48/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080049static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070050static int append = 0;
51
52#define HOSTFS_SUPER_MAGIC 0x00c0ffee
53
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080054static const struct inode_operations hostfs_iops;
55static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070056static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58#ifndef MODULE
59static int __init hostfs_args(char *options, int *add)
60{
61 char *ptr;
62
63 ptr = strchr(options, ',');
64 if(ptr != NULL)
65 *ptr++ = '\0';
66 if(*options != '\0')
67 root_ino = options;
68
69 options = ptr;
70 while(options){
71 ptr = strchr(options, ',');
72 if(ptr != NULL)
73 *ptr++ = '\0';
74 if(*options != '\0'){
75 if(!strcmp(options, "append"))
76 append = 1;
77 else printf("hostfs_args - unsupported option - %s\n",
78 options);
79 }
80 options = ptr;
81 }
82 return(0);
83}
84
85__uml_setup("hostfs=", hostfs_args,
86"hostfs=<root dir>,<flags>,...\n"
87" This is used to set hostfs parameters. The root directory argument\n"
88" is used to confine all hostfs mounts to within the specified directory\n"
89" tree on the host. If this isn't specified, then a user inside UML can\n"
90" mount anything on the host that's accessible to the user that's running\n"
91" it.\n"
92" The only flag currently supported is 'append', which specifies that all\n"
93" files opened by hostfs will be opened in append mode.\n\n"
94);
95#endif
96
97static char *dentry_name(struct dentry *dentry, int extra)
98{
99 struct dentry *parent;
100 char *root, *name;
101 int len;
102
103 len = 0;
104 parent = dentry;
105 while(parent->d_parent != parent){
106 len += parent->d_name.len + 1;
107 parent = parent->d_parent;
108 }
109
110 root = HOSTFS_I(parent->d_inode)->host_filename;
111 len += strlen(root);
112 name = kmalloc(len + extra + 1, GFP_KERNEL);
113 if(name == NULL) return(NULL);
114
115 name[len] = '\0';
116 parent = dentry;
117 while(parent->d_parent != parent){
118 len -= parent->d_name.len + 1;
119 name[len] = '/';
120 strncpy(&name[len + 1], parent->d_name.name,
121 parent->d_name.len);
122 parent = parent->d_parent;
123 }
124 strncpy(name, root, strlen(root));
125 return(name);
126}
127
128static char *inode_name(struct inode *ino, int extra)
129{
130 struct dentry *dentry;
131
132 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
133 return(dentry_name(dentry, extra));
134}
135
136static int read_name(struct inode *ino, char *name)
137{
138 /* The non-int inode fields are copied into ints by stat_file and
139 * then copied into the inode because passing the actual pointers
140 * in and having them treated as int * breaks on big-endian machines
141 */
142 int err;
143 int i_mode, i_nlink, i_blksize;
144 unsigned long long i_size;
145 unsigned long long i_ino;
146 unsigned long long i_blocks;
147
148 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
149 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
150 &ino->i_ctime, &i_blksize, &i_blocks);
151 if(err)
152 return(err);
153
154 ino->i_ino = i_ino;
155 ino->i_mode = i_mode;
156 ino->i_nlink = i_nlink;
157 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 ino->i_blocks = i_blocks;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 return(0);
160}
161
162static char *follow_link(char *link)
163{
164 int len, n;
165 char *name, *resolved, *end;
166
167 len = 64;
168 while(1){
169 n = -ENOMEM;
170 name = kmalloc(len, GFP_KERNEL);
171 if(name == NULL)
172 goto out;
173
174 n = do_readlink(link, name, len);
175 if(n < len)
176 break;
177 len *= 2;
178 kfree(name);
179 }
180 if(n < 0)
181 goto out_free;
182
183 if(*name == '/')
184 return(name);
185
186 end = strrchr(link, '/');
187 if(end == NULL)
188 return(name);
189
190 *(end + 1) = '\0';
191 len = strlen(link) + strlen(name) + 1;
192
193 resolved = kmalloc(len, GFP_KERNEL);
194 if(resolved == NULL){
195 n = -ENOMEM;
196 goto out_free;
197 }
198
199 sprintf(resolved, "%s%s", link, name);
200 kfree(name);
201 kfree(link);
202 return(resolved);
203
204 out_free:
205 kfree(name);
206 out:
207 return(ERR_PTR(n));
208}
209
210static int read_inode(struct inode *ino)
211{
212 char *name;
213 int err = 0;
214
215 /* Unfortunately, we are called from iget() when we don't have a dentry
216 * allocated yet.
217 */
218 if(list_empty(&ino->i_dentry))
219 goto out;
220
221 err = -ENOMEM;
222 name = inode_name(ino, 0);
223 if(name == NULL)
224 goto out;
225
226 if(file_type(name, NULL, NULL) == OS_TYPE_SYMLINK){
227 name = follow_link(name);
228 if(IS_ERR(name)){
229 err = PTR_ERR(name);
230 goto out;
231 }
232 }
233
234 err = read_name(ino, name);
235 kfree(name);
236 out:
237 return(err);
238}
239
David Howells726c3342006-06-23 02:02:58 -0700240int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
242 /* do_statfs uses struct statfs64 internally, but the linux kernel
243 * struct statfs still has 32-bit versions for most of these fields,
244 * so we convert them here
245 */
246 int err;
247 long long f_blocks;
248 long long f_bfree;
249 long long f_bavail;
250 long long f_files;
251 long long f_ffree;
252
David Howells726c3342006-06-23 02:02:58 -0700253 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
255 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
256 &sf->f_namelen, sf->f_spare);
257 if(err) return(err);
258 sf->f_blocks = f_blocks;
259 sf->f_bfree = f_bfree;
260 sf->f_bavail = f_bavail;
261 sf->f_files = f_files;
262 sf->f_ffree = f_ffree;
263 sf->f_type = HOSTFS_SUPER_MAGIC;
264 return(0);
265}
266
267static struct inode *hostfs_alloc_inode(struct super_block *sb)
268{
269 struct hostfs_inode_info *hi;
270
271 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
272 if(hi == NULL)
273 return(NULL);
274
275 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
276 .fd = -1,
277 .mode = 0 });
278 inode_init_once(&hi->vfs_inode);
279 return(&hi->vfs_inode);
280}
281
282static void hostfs_delete_inode(struct inode *inode)
283{
Mark Fashehfef26652005-09-09 13:01:31 -0700284 truncate_inode_pages(&inode->i_data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 if(HOSTFS_I(inode)->fd != -1) {
286 close_file(&HOSTFS_I(inode)->fd);
287 HOSTFS_I(inode)->fd = -1;
288 }
289 clear_inode(inode);
290}
291
292static void hostfs_destroy_inode(struct inode *inode)
293{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800294 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 /*XXX: This should not happen, probably. The check is here for
297 * additional safety.*/
298 if(HOSTFS_I(inode)->fd != -1) {
299 close_file(&HOSTFS_I(inode)->fd);
300 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
301 }
302
303 kfree(HOSTFS_I(inode));
304}
305
306static void hostfs_read_inode(struct inode *inode)
307{
308 read_inode(inode);
309}
310
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800311static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 .alloc_inode = hostfs_alloc_inode,
313 .drop_inode = generic_delete_inode,
314 .delete_inode = hostfs_delete_inode,
315 .destroy_inode = hostfs_destroy_inode,
316 .read_inode = hostfs_read_inode,
317 .statfs = hostfs_statfs,
318};
319
320int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
321{
322 void *dir;
323 char *name;
324 unsigned long long next, ino;
325 int error, len;
326
Josef Sipek680b0da2006-12-08 02:37:05 -0800327 name = dentry_name(file->f_path.dentry, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 if(name == NULL) return(-ENOMEM);
329 dir = open_dir(name, &error);
330 kfree(name);
331 if(dir == NULL) return(-error);
332 next = file->f_pos;
333 while((name = read_dir(dir, &next, &ino, &len)) != NULL){
334 error = (*filldir)(ent, name, len, file->f_pos,
335 ino, DT_UNKNOWN);
336 if(error) break;
337 file->f_pos = next;
338 }
339 close_dir(dir);
340 return(0);
341}
342
343int hostfs_file_open(struct inode *ino, struct file *file)
344{
345 char *name;
346 int mode = 0, r = 0, w = 0, fd;
347
348 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
349 if((mode & HOSTFS_I(ino)->mode) == mode)
350 return(0);
351
352 /* The file may already have been opened, but with the wrong access,
353 * so this resets things and reopens the file with the new access.
354 */
355 if(HOSTFS_I(ino)->fd != -1){
356 close_file(&HOSTFS_I(ino)->fd);
357 HOSTFS_I(ino)->fd = -1;
358 }
359
360 HOSTFS_I(ino)->mode |= mode;
361 if(HOSTFS_I(ino)->mode & FMODE_READ)
362 r = 1;
363 if(HOSTFS_I(ino)->mode & FMODE_WRITE)
364 w = 1;
365 if(w)
366 r = 1;
367
Josef Sipek680b0da2006-12-08 02:37:05 -0800368 name = dentry_name(file->f_path.dentry, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 if(name == NULL)
370 return(-ENOMEM);
371
372 fd = open_file(name, r, w, append);
373 kfree(name);
374 if(fd < 0) return(fd);
375 FILE_HOSTFS_I(file)->fd = fd;
376
377 return(0);
378}
379
380int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
381{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700382 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800385static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700387 .read = do_sync_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .sendfile = generic_file_sendfile,
389 .aio_read = generic_file_aio_read,
390 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700391 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 .mmap = generic_file_mmap,
393 .open = hostfs_file_open,
394 .release = NULL,
395 .fsync = hostfs_fsync,
396};
397
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800398static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 .llseek = generic_file_llseek,
400 .readdir = hostfs_readdir,
401 .read = generic_read_dir,
402};
403
404int hostfs_writepage(struct page *page, struct writeback_control *wbc)
405{
406 struct address_space *mapping = page->mapping;
407 struct inode *inode = mapping->host;
408 char *buffer;
409 unsigned long long base;
410 int count = PAGE_CACHE_SIZE;
411 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
412 int err;
413
414 if (page->index >= end_index)
415 count = inode->i_size & (PAGE_CACHE_SIZE-1);
416
417 buffer = kmap(page);
418 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
419
420 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
421 if(err != count){
422 ClearPageUptodate(page);
423 goto out;
424 }
425
426 if (base > inode->i_size)
427 inode->i_size = base;
428
429 if (PageError(page))
430 ClearPageError(page);
431 err = 0;
432
433 out:
434 kunmap(page);
435
436 unlock_page(page);
437 return err;
438}
439
440int hostfs_readpage(struct file *file, struct page *page)
441{
442 char *buffer;
443 long long start;
444 int err = 0;
445
446 start = (long long) page->index << PAGE_CACHE_SHIFT;
447 buffer = kmap(page);
448 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
449 PAGE_CACHE_SIZE);
450 if(err < 0) goto out;
451
452 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
453
454 flush_dcache_page(page);
455 SetPageUptodate(page);
456 if (PageError(page)) ClearPageError(page);
457 err = 0;
458 out:
459 kunmap(page);
460 unlock_page(page);
461 return(err);
462}
463
464int hostfs_prepare_write(struct file *file, struct page *page,
465 unsigned int from, unsigned int to)
466{
467 char *buffer;
468 long long start, tmp;
469 int err;
470
471 start = (long long) page->index << PAGE_CACHE_SHIFT;
472 buffer = kmap(page);
473 if(from != 0){
474 tmp = start;
475 err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer,
476 from);
477 if(err < 0) goto out;
478 }
479 if(to != PAGE_CACHE_SIZE){
480 start += to;
481 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to,
482 PAGE_CACHE_SIZE - to);
483 if(err < 0) goto out;
484 }
485 err = 0;
486 out:
487 kunmap(page);
488 return(err);
489}
490
491int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
492 unsigned to)
493{
494 struct address_space *mapping = page->mapping;
495 struct inode *inode = mapping->host;
496 char *buffer;
497 long long start;
498 int err = 0;
499
Paolo 'Blaisorblade' Giarrusso30f04a42005-12-29 17:39:57 +0100500 start = (((long long) page->index) << PAGE_CACHE_SHIFT) + from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 buffer = kmap(page);
502 err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from,
503 to - from);
504 if(err > 0) err = 0;
Paolo 'Blaisorblade' Giarrusso30f04a42005-12-29 17:39:57 +0100505
506 /* Actually, if !err, write_file has added to-from to start, so, despite
507 * the appearance, we are comparing i_size against the _last_ written
508 * location, as we should. */
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if(!err && (start > inode->i_size))
511 inode->i_size = start;
512
513 kunmap(page);
514 return(err);
515}
516
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700517static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 .writepage = hostfs_writepage,
519 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700520 .set_page_dirty = __set_page_dirty_nobuffers,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 .prepare_write = hostfs_prepare_write,
522 .commit_write = hostfs_commit_write
523};
524
525static int init_inode(struct inode *inode, struct dentry *dentry)
526{
527 char *name;
528 int type, err = -ENOMEM;
529 int maj, min;
530 dev_t rdev = 0;
531
532 if(dentry){
533 name = dentry_name(dentry, 0);
534 if(name == NULL)
535 goto out;
536 type = file_type(name, &maj, &min);
537 /*Reencode maj and min with the kernel encoding.*/
538 rdev = MKDEV(maj, min);
539 kfree(name);
540 }
541 else type = OS_TYPE_DIR;
542
543 err = 0;
544 if(type == OS_TYPE_SYMLINK)
545 inode->i_op = &page_symlink_inode_operations;
546 else if(type == OS_TYPE_DIR)
547 inode->i_op = &hostfs_dir_iops;
548 else inode->i_op = &hostfs_iops;
549
550 if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
551 else inode->i_fop = &hostfs_file_fops;
552
553 if(type == OS_TYPE_SYMLINK)
554 inode->i_mapping->a_ops = &hostfs_link_aops;
555 else inode->i_mapping->a_ops = &hostfs_aops;
556
557 switch (type) {
558 case OS_TYPE_CHARDEV:
559 init_special_inode(inode, S_IFCHR, rdev);
560 break;
561 case OS_TYPE_BLOCKDEV:
562 init_special_inode(inode, S_IFBLK, rdev);
563 break;
564 case OS_TYPE_FIFO:
565 init_special_inode(inode, S_IFIFO, 0);
566 break;
567 case OS_TYPE_SOCK:
568 init_special_inode(inode, S_IFSOCK, 0);
569 break;
570 }
571 out:
572 return(err);
573}
574
575int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
576 struct nameidata *nd)
577{
578 struct inode *inode;
579 char *name;
580 int error, fd;
581
582 error = -ENOMEM;
583 inode = iget(dir->i_sb, 0);
584 if(inode == NULL) goto out;
585
586 error = init_inode(inode, dentry);
587 if(error)
588 goto out_put;
589
590 error = -ENOMEM;
591 name = dentry_name(dentry, 0);
592 if(name == NULL)
593 goto out_put;
594
595 fd = file_create(name,
596 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
597 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
598 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
599 if(fd < 0)
600 error = fd;
601 else error = read_name(inode, name);
602
603 kfree(name);
604 if(error)
605 goto out_put;
606
607 HOSTFS_I(inode)->fd = fd;
608 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
609 d_instantiate(dentry, inode);
610 return(0);
611
612 out_put:
613 iput(inode);
614 out:
615 return(error);
616}
617
618struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
619 struct nameidata *nd)
620{
621 struct inode *inode;
622 char *name;
623 int err;
624
625 err = -ENOMEM;
626 inode = iget(ino->i_sb, 0);
627 if(inode == NULL)
628 goto out;
629
630 err = init_inode(inode, dentry);
631 if(err)
632 goto out_put;
633
634 err = -ENOMEM;
635 name = dentry_name(dentry, 0);
636 if(name == NULL)
637 goto out_put;
638
639 err = read_name(inode, name);
640 kfree(name);
641 if(err == -ENOENT){
642 iput(inode);
643 inode = NULL;
644 }
645 else if(err)
646 goto out_put;
647
648 d_add(dentry, inode);
649 dentry->d_op = &hostfs_dentry_ops;
650 return(NULL);
651
652 out_put:
653 iput(inode);
654 out:
655 return(ERR_PTR(err));
656}
657
658static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
659{
660 char *file;
661 int len;
662
663 file = inode_name(ino, dentry->d_name.len + 1);
664 if(file == NULL) return(NULL);
665 strcat(file, "/");
666 len = strlen(file);
667 strncat(file, dentry->d_name.name, dentry->d_name.len);
668 file[len + dentry->d_name.len] = '\0';
669 return(file);
670}
671
672int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
673{
674 char *from_name, *to_name;
675 int err;
676
677 if((from_name = inode_dentry_name(ino, from)) == NULL)
678 return(-ENOMEM);
679 to_name = dentry_name(to, 0);
680 if(to_name == NULL){
681 kfree(from_name);
682 return(-ENOMEM);
683 }
684 err = link_file(to_name, from_name);
685 kfree(from_name);
686 kfree(to_name);
687 return(err);
688}
689
690int hostfs_unlink(struct inode *ino, struct dentry *dentry)
691{
692 char *file;
693 int err;
694
695 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
696 if(append)
697 return(-EPERM);
698
699 err = unlink_file(file);
700 kfree(file);
701 return(err);
702}
703
704int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
705{
706 char *file;
707 int err;
708
709 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
710 err = make_symlink(file, to);
711 kfree(file);
712 return(err);
713}
714
715int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
716{
717 char *file;
718 int err;
719
720 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
721 err = do_mkdir(file, mode);
722 kfree(file);
723 return(err);
724}
725
726int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
727{
728 char *file;
729 int err;
730
731 if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
732 err = do_rmdir(file);
733 kfree(file);
734 return(err);
735}
736
737int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
738{
739 struct inode *inode;
740 char *name;
741 int err = -ENOMEM;
742
743 inode = iget(dir->i_sb, 0);
744 if(inode == NULL)
745 goto out;
746
747 err = init_inode(inode, dentry);
748 if(err)
749 goto out_put;
750
751 err = -ENOMEM;
752 name = dentry_name(dentry, 0);
753 if(name == NULL)
754 goto out_put;
755
756 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800757 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if(err)
759 goto out_free;
760
761 err = read_name(inode, name);
762 kfree(name);
763 if(err)
764 goto out_put;
765
766 d_instantiate(dentry, inode);
767 return(0);
768
769 out_free:
770 kfree(name);
771 out_put:
772 iput(inode);
773 out:
774 return(err);
775}
776
777int hostfs_rename(struct inode *from_ino, struct dentry *from,
778 struct inode *to_ino, struct dentry *to)
779{
780 char *from_name, *to_name;
781 int err;
782
783 if((from_name = inode_dentry_name(from_ino, from)) == NULL)
784 return(-ENOMEM);
785 if((to_name = inode_dentry_name(to_ino, to)) == NULL){
786 kfree(from_name);
787 return(-ENOMEM);
788 }
789 err = rename_file(from_name, to_name);
790 kfree(from_name);
791 kfree(to_name);
792 return(err);
793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
796{
797 char *name;
798 int r = 0, w = 0, x = 0, err;
799
800 if (desired & MAY_READ) r = 1;
801 if (desired & MAY_WRITE) w = 1;
802 if (desired & MAY_EXEC) x = 1;
803 name = inode_name(ino, 0);
804 if (name == NULL) return(-ENOMEM);
805
806 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
807 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
808 err = 0;
809 else
810 err = access_file(name, r, w, x);
811 kfree(name);
812 if(!err)
813 err = generic_permission(ino, desired, NULL);
814 return err;
815}
816
817int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
818{
819 struct hostfs_iattr attrs;
820 char *name;
821 int err;
822
823 err = inode_change_ok(dentry->d_inode, attr);
824 if (err)
825 return err;
826
827 if(append)
828 attr->ia_valid &= ~ATTR_SIZE;
829
830 attrs.ia_valid = 0;
831 if(attr->ia_valid & ATTR_MODE){
832 attrs.ia_valid |= HOSTFS_ATTR_MODE;
833 attrs.ia_mode = attr->ia_mode;
834 }
835 if(attr->ia_valid & ATTR_UID){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_UID;
837 attrs.ia_uid = attr->ia_uid;
838 }
839 if(attr->ia_valid & ATTR_GID){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_GID;
841 attrs.ia_gid = attr->ia_gid;
842 }
843 if(attr->ia_valid & ATTR_SIZE){
844 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
845 attrs.ia_size = attr->ia_size;
846 }
847 if(attr->ia_valid & ATTR_ATIME){
848 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
849 attrs.ia_atime = attr->ia_atime;
850 }
851 if(attr->ia_valid & ATTR_MTIME){
852 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
853 attrs.ia_mtime = attr->ia_mtime;
854 }
855 if(attr->ia_valid & ATTR_CTIME){
856 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
857 attrs.ia_ctime = attr->ia_ctime;
858 }
859 if(attr->ia_valid & ATTR_ATIME_SET){
860 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
861 }
862 if(attr->ia_valid & ATTR_MTIME_SET){
863 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
864 }
865 name = dentry_name(dentry, 0);
866 if(name == NULL) return(-ENOMEM);
867 err = set_attr(name, &attrs);
868 kfree(name);
869 if(err)
870 return(err);
871
872 return(inode_setattr(dentry->d_inode, attr));
873}
874
875int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
876 struct kstat *stat)
877{
878 generic_fillattr(dentry->d_inode, stat);
879 return(0);
880}
881
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800882static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 .create = hostfs_create,
884 .link = hostfs_link,
885 .unlink = hostfs_unlink,
886 .symlink = hostfs_symlink,
887 .mkdir = hostfs_mkdir,
888 .rmdir = hostfs_rmdir,
889 .mknod = hostfs_mknod,
890 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 .permission = hostfs_permission,
892 .setattr = hostfs_setattr,
893 .getattr = hostfs_getattr,
894};
895
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800896static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 .create = hostfs_create,
898 .lookup = hostfs_lookup,
899 .link = hostfs_link,
900 .unlink = hostfs_unlink,
901 .symlink = hostfs_symlink,
902 .mkdir = hostfs_mkdir,
903 .rmdir = hostfs_rmdir,
904 .mknod = hostfs_mknod,
905 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 .permission = hostfs_permission,
907 .setattr = hostfs_setattr,
908 .getattr = hostfs_getattr,
909};
910
911int hostfs_link_readpage(struct file *file, struct page *page)
912{
913 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 int err;
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 buffer = kmap(page);
917 name = inode_name(page->mapping->host, 0);
918 if(name == NULL) return(-ENOMEM);
919 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
920 kfree(name);
921 if(err == PAGE_CACHE_SIZE)
922 err = -E2BIG;
923 else if(err > 0){
924 flush_dcache_page(page);
925 SetPageUptodate(page);
926 if (PageError(page)) ClearPageError(page);
927 err = 0;
928 }
929 kunmap(page);
930 unlock_page(page);
931 return(err);
932}
933
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700934static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 .readpage = hostfs_link_readpage,
936};
937
938static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
939{
940 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700941 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 int err;
943
944 sb->s_blocksize = 1024;
945 sb->s_blocksize_bits = 10;
946 sb->s_magic = HOSTFS_SUPER_MAGIC;
947 sb->s_op = &hostfs_sbops;
948
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800949 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700950 if (req_root == NULL)
951 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700954 host_root_path = kmalloc(strlen(root_ino) + 1
955 + strlen(req_root) + 1, GFP_KERNEL);
956 if(host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 goto out;
958
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700959 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 root_inode = iget(sb, 0);
962 if(root_inode == NULL)
963 goto out_free;
964
965 err = init_inode(root_inode, NULL);
966 if(err)
967 goto out_put;
968
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700969 HOSTFS_I(root_inode)->host_filename = host_root_path;
970 /* Avoid that in the error path, iput(root_inode) frees again
971 * host_root_path through hostfs_destroy_inode! */
972 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 err = -ENOMEM;
975 sb->s_root = d_alloc_root(root_inode);
976 if(sb->s_root == NULL)
977 goto out_put;
978
979 err = read_inode(root_inode);
Jeff Dike51a14112005-05-05 16:15:34 -0700980 if(err){
981 /* No iput in this case because the dput does that for us */
982 dput(sb->s_root);
983 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -0800984 goto out;
Jeff Dike51a14112005-05-05 16:15:34 -0700985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 return(0);
988
989 out_put:
Jeff Dike51a14112005-05-05 16:15:34 -0700990 iput(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700992 kfree(host_root_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 out:
994 return(err);
995}
996
David Howells454e2392006-06-23 02:02:57 -0700997static int hostfs_read_sb(struct file_system_type *type,
998 int flags, const char *dev_name,
999 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
David Howells454e2392006-06-23 02:02:57 -07001001 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002}
1003
1004static struct file_system_type hostfs_type = {
1005 .owner = THIS_MODULE,
1006 .name = "hostfs",
1007 .get_sb = hostfs_read_sb,
1008 .kill_sb = kill_anon_super,
1009 .fs_flags = 0,
1010};
1011
1012static int __init init_hostfs(void)
1013{
1014 return(register_filesystem(&hostfs_type));
1015}
1016
1017static void __exit exit_hostfs(void)
1018{
1019 unregister_filesystem(&hostfs_type);
1020}
1021
1022module_init(init_hostfs)
1023module_exit(exit_hostfs)
1024MODULE_LICENSE("GPL");
1025
1026/*
1027 * Overrides for Emacs so that we follow Linus's tabbing style.
1028 * Emacs will notice this stuff at the end of the file and automatically
1029 * adjust the settings for this buffer only. This must remain at the end
1030 * of the file.
1031 * ---------------------------------------------------------------------------
1032 * Local variables:
1033 * c-file-style: "linux"
1034 * End:
1035 */