blob: 8286491dbf31dbccca606b241ae755d5cd77cee8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikef1adc052007-05-08 00:23:18 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * 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{
Jeff Dikef1adc052007-05-08 00:23:18 -070034 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035}
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{
Jeff Dikef1adc052007-05-08 00:23:18 -070041 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042}
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 }
Jeff Dikef1adc052007-05-08 00:23:18 -070082 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
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);
Jeff Dikef1adc052007-05-08 00:23:18 -0700113 if(name == NULL)
114 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116 name[len] = '\0';
117 parent = dentry;
118 while(parent->d_parent != parent){
119 len -= parent->d_name.len + 1;
120 name[len] = '/';
121 strncpy(&name[len + 1], parent->d_name.name,
122 parent->d_name.len);
123 parent = parent->d_parent;
124 }
125 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700126 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
129static char *inode_name(struct inode *ino, int extra)
130{
131 struct dentry *dentry;
132
133 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700134 return dentry_name(dentry, extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135}
136
137static int read_name(struct inode *ino, char *name)
138{
139 /* The non-int inode fields are copied into ints by stat_file and
140 * then copied into the inode because passing the actual pointers
141 * in and having them treated as int * breaks on big-endian machines
142 */
143 int err;
144 int i_mode, i_nlink, i_blksize;
145 unsigned long long i_size;
146 unsigned long long i_ino;
147 unsigned long long i_blocks;
148
149 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
150 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700151 &ino->i_ctime, &i_blksize, &i_blocks, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 if(err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700153 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 ino->i_ino = i_ino;
156 ino->i_mode = i_mode;
157 ino->i_nlink = i_nlink;
158 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 ino->i_blocks = i_blocks;
Jeff Dikef1adc052007-05-08 00:23:18 -0700160 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}
162
163static char *follow_link(char *link)
164{
165 int len, n;
166 char *name, *resolved, *end;
167
168 len = 64;
169 while(1){
170 n = -ENOMEM;
171 name = kmalloc(len, GFP_KERNEL);
172 if(name == NULL)
173 goto out;
174
175 n = do_readlink(link, name, len);
176 if(n < len)
177 break;
178 len *= 2;
179 kfree(name);
180 }
181 if(n < 0)
182 goto out_free;
183
184 if(*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700185 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
187 end = strrchr(link, '/');
188 if(end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700189 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 *(end + 1) = '\0';
192 len = strlen(link) + strlen(name) + 1;
193
194 resolved = kmalloc(len, GFP_KERNEL);
195 if(resolved == NULL){
196 n = -ENOMEM;
197 goto out_free;
198 }
199
200 sprintf(resolved, "%s%s", link, name);
201 kfree(name);
202 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700203 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 out_free:
206 kfree(name);
207 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700208 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
211static int read_inode(struct inode *ino)
212{
213 char *name;
214 int err = 0;
215
216 /* Unfortunately, we are called from iget() when we don't have a dentry
217 * allocated yet.
218 */
219 if(list_empty(&ino->i_dentry))
220 goto out;
221
222 err = -ENOMEM;
223 name = inode_name(ino, 0);
224 if(name == NULL)
225 goto out;
226
227 if(file_type(name, NULL, NULL) == OS_TYPE_SYMLINK){
228 name = follow_link(name);
229 if(IS_ERR(name)){
230 err = PTR_ERR(name);
231 goto out;
232 }
233 }
234
235 err = read_name(ino, name);
236 kfree(name);
237 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700238 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239}
240
David Howells726c3342006-06-23 02:02:58 -0700241int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
243 /* do_statfs uses struct statfs64 internally, but the linux kernel
244 * struct statfs still has 32-bit versions for most of these fields,
245 * so we convert them here
246 */
247 int err;
248 long long f_blocks;
249 long long f_bfree;
250 long long f_bavail;
251 long long f_files;
252 long long f_ffree;
253
David Howells726c3342006-06-23 02:02:58 -0700254 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
256 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
257 &sf->f_namelen, sf->f_spare);
Jeff Dikef1adc052007-05-08 00:23:18 -0700258 if(err)
259 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 sf->f_blocks = f_blocks;
261 sf->f_bfree = f_bfree;
262 sf->f_bavail = f_bavail;
263 sf->f_files = f_files;
264 sf->f_ffree = f_ffree;
265 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700266 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267}
268
269static struct inode *hostfs_alloc_inode(struct super_block *sb)
270{
271 struct hostfs_inode_info *hi;
272
273 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
274 if(hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700275 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
278 .fd = -1,
279 .mode = 0 });
280 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700281 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282}
283
284static void hostfs_delete_inode(struct inode *inode)
285{
Mark Fashehfef26652005-09-09 13:01:31 -0700286 truncate_inode_pages(&inode->i_data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 if(HOSTFS_I(inode)->fd != -1) {
288 close_file(&HOSTFS_I(inode)->fd);
289 HOSTFS_I(inode)->fd = -1;
290 }
291 clear_inode(inode);
292}
293
294static void hostfs_destroy_inode(struct inode *inode)
295{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800296 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 /*XXX: This should not happen, probably. The check is here for
299 * additional safety.*/
300 if(HOSTFS_I(inode)->fd != -1) {
301 close_file(&HOSTFS_I(inode)->fd);
302 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
303 }
304
305 kfree(HOSTFS_I(inode));
306}
307
308static void hostfs_read_inode(struct inode *inode)
309{
310 read_inode(inode);
311}
312
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800313static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 .alloc_inode = hostfs_alloc_inode,
315 .drop_inode = generic_delete_inode,
316 .delete_inode = hostfs_delete_inode,
317 .destroy_inode = hostfs_destroy_inode,
318 .read_inode = hostfs_read_inode,
319 .statfs = hostfs_statfs,
320};
321
322int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
323{
324 void *dir;
325 char *name;
326 unsigned long long next, ino;
327 int error, len;
328
Josef Sipek680b0da2006-12-08 02:37:05 -0800329 name = dentry_name(file->f_path.dentry, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700330 if(name == NULL)
331 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 dir = open_dir(name, &error);
333 kfree(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700334 if(dir == NULL)
335 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 next = file->f_pos;
337 while((name = read_dir(dir, &next, &ino, &len)) != NULL){
338 error = (*filldir)(ent, name, len, file->f_pos,
339 ino, DT_UNKNOWN);
340 if(error) break;
341 file->f_pos = next;
342 }
343 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700344 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345}
346
347int hostfs_file_open(struct inode *ino, struct file *file)
348{
349 char *name;
350 int mode = 0, r = 0, w = 0, fd;
351
352 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
353 if((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700354 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /* The file may already have been opened, but with the wrong access,
357 * so this resets things and reopens the file with the new access.
358 */
359 if(HOSTFS_I(ino)->fd != -1){
360 close_file(&HOSTFS_I(ino)->fd);
361 HOSTFS_I(ino)->fd = -1;
362 }
363
364 HOSTFS_I(ino)->mode |= mode;
365 if(HOSTFS_I(ino)->mode & FMODE_READ)
366 r = 1;
367 if(HOSTFS_I(ino)->mode & FMODE_WRITE)
368 w = 1;
369 if(w)
370 r = 1;
371
Josef Sipek680b0da2006-12-08 02:37:05 -0800372 name = dentry_name(file->f_path.dentry, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 if(name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700374 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 fd = open_file(name, r, w, append);
377 kfree(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700378 if(fd < 0)
379 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 FILE_HOSTFS_I(file)->fd = fd;
381
Jeff Dikef1adc052007-05-08 00:23:18 -0700382 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
385int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
386{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700387 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800390static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700392 .read = do_sync_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 .sendfile = generic_file_sendfile,
394 .aio_read = generic_file_aio_read,
395 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700396 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 .mmap = generic_file_mmap,
398 .open = hostfs_file_open,
399 .release = NULL,
400 .fsync = hostfs_fsync,
401};
402
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800403static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 .llseek = generic_file_llseek,
405 .readdir = hostfs_readdir,
406 .read = generic_read_dir,
407};
408
409int hostfs_writepage(struct page *page, struct writeback_control *wbc)
410{
411 struct address_space *mapping = page->mapping;
412 struct inode *inode = mapping->host;
413 char *buffer;
414 unsigned long long base;
415 int count = PAGE_CACHE_SIZE;
416 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
417 int err;
418
419 if (page->index >= end_index)
420 count = inode->i_size & (PAGE_CACHE_SIZE-1);
421
422 buffer = kmap(page);
423 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
424
425 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
426 if(err != count){
427 ClearPageUptodate(page);
428 goto out;
429 }
430
431 if (base > inode->i_size)
432 inode->i_size = base;
433
434 if (PageError(page))
435 ClearPageError(page);
436 err = 0;
437
438 out:
439 kunmap(page);
440
441 unlock_page(page);
442 return err;
443}
444
445int hostfs_readpage(struct file *file, struct page *page)
446{
447 char *buffer;
448 long long start;
449 int err = 0;
450
451 start = (long long) page->index << PAGE_CACHE_SHIFT;
452 buffer = kmap(page);
453 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
454 PAGE_CACHE_SIZE);
455 if(err < 0) goto out;
456
457 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
458
459 flush_dcache_page(page);
460 SetPageUptodate(page);
461 if (PageError(page)) ClearPageError(page);
462 err = 0;
463 out:
464 kunmap(page);
465 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700466 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467}
468
469int hostfs_prepare_write(struct file *file, struct page *page,
470 unsigned int from, unsigned int to)
471{
472 char *buffer;
473 long long start, tmp;
474 int err;
475
476 start = (long long) page->index << PAGE_CACHE_SHIFT;
477 buffer = kmap(page);
478 if(from != 0){
479 tmp = start;
480 err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer,
481 from);
482 if(err < 0) goto out;
483 }
484 if(to != PAGE_CACHE_SIZE){
485 start += to;
486 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to,
487 PAGE_CACHE_SIZE - to);
488 if(err < 0) goto out;
489 }
490 err = 0;
491 out:
492 kunmap(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700493 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
496int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
497 unsigned to)
498{
499 struct address_space *mapping = page->mapping;
500 struct inode *inode = mapping->host;
501 char *buffer;
502 long long start;
503 int err = 0;
504
Paolo 'Blaisorblade' Giarrusso30f04a42005-12-29 17:39:57 +0100505 start = (((long long) page->index) << PAGE_CACHE_SHIFT) + from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 buffer = kmap(page);
507 err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from,
508 to - from);
509 if(err > 0) err = 0;
Paolo 'Blaisorblade' Giarrusso30f04a42005-12-29 17:39:57 +0100510
511 /* Actually, if !err, write_file has added to-from to start, so, despite
512 * the appearance, we are comparing i_size against the _last_ written
513 * location, as we should. */
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 if(!err && (start > inode->i_size))
516 inode->i_size = start;
517
518 kunmap(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700519 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700522static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 .writepage = hostfs_writepage,
524 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700525 .set_page_dirty = __set_page_dirty_nobuffers,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 .prepare_write = hostfs_prepare_write,
527 .commit_write = hostfs_commit_write
528};
529
530static int init_inode(struct inode *inode, struct dentry *dentry)
531{
532 char *name;
533 int type, err = -ENOMEM;
534 int maj, min;
535 dev_t rdev = 0;
536
537 if(dentry){
538 name = dentry_name(dentry, 0);
539 if(name == NULL)
540 goto out;
541 type = file_type(name, &maj, &min);
542 /*Reencode maj and min with the kernel encoding.*/
543 rdev = MKDEV(maj, min);
544 kfree(name);
545 }
546 else type = OS_TYPE_DIR;
547
548 err = 0;
549 if(type == OS_TYPE_SYMLINK)
550 inode->i_op = &page_symlink_inode_operations;
551 else if(type == OS_TYPE_DIR)
552 inode->i_op = &hostfs_dir_iops;
553 else inode->i_op = &hostfs_iops;
554
555 if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
556 else inode->i_fop = &hostfs_file_fops;
557
558 if(type == OS_TYPE_SYMLINK)
559 inode->i_mapping->a_ops = &hostfs_link_aops;
560 else inode->i_mapping->a_ops = &hostfs_aops;
561
562 switch (type) {
563 case OS_TYPE_CHARDEV:
564 init_special_inode(inode, S_IFCHR, rdev);
565 break;
566 case OS_TYPE_BLOCKDEV:
567 init_special_inode(inode, S_IFBLK, rdev);
568 break;
569 case OS_TYPE_FIFO:
570 init_special_inode(inode, S_IFIFO, 0);
571 break;
572 case OS_TYPE_SOCK:
573 init_special_inode(inode, S_IFSOCK, 0);
574 break;
575 }
576 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700577 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578}
579
580int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
581 struct nameidata *nd)
582{
583 struct inode *inode;
584 char *name;
585 int error, fd;
586
587 error = -ENOMEM;
588 inode = iget(dir->i_sb, 0);
589 if(inode == NULL) goto out;
590
591 error = init_inode(inode, dentry);
592 if(error)
593 goto out_put;
594
595 error = -ENOMEM;
596 name = dentry_name(dentry, 0);
597 if(name == NULL)
598 goto out_put;
599
600 fd = file_create(name,
601 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
602 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
603 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
604 if(fd < 0)
605 error = fd;
606 else error = read_name(inode, name);
607
608 kfree(name);
609 if(error)
610 goto out_put;
611
612 HOSTFS_I(inode)->fd = fd;
613 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
614 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700615 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 out_put:
618 iput(inode);
619 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700620 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
623struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700624 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 struct inode *inode;
627 char *name;
628 int err;
629
630 err = -ENOMEM;
631 inode = iget(ino->i_sb, 0);
632 if(inode == NULL)
633 goto out;
634
635 err = init_inode(inode, dentry);
636 if(err)
637 goto out_put;
638
639 err = -ENOMEM;
640 name = dentry_name(dentry, 0);
641 if(name == NULL)
642 goto out_put;
643
644 err = read_name(inode, name);
645 kfree(name);
646 if(err == -ENOENT){
647 iput(inode);
648 inode = NULL;
649 }
650 else if(err)
651 goto out_put;
652
653 d_add(dentry, inode);
654 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 out_put:
658 iput(inode);
659 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700660 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
663static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
664{
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int len;
667
668 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dikef1adc052007-05-08 00:23:18 -0700669 if(file == NULL)
670 return NULL;
671 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700675 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676}
677
678int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
679{
Jeff Dikef1adc052007-05-08 00:23:18 -0700680 char *from_name, *to_name;
681 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jeff Dikef1adc052007-05-08 00:23:18 -0700683 if((from_name = inode_dentry_name(ino, from)) == NULL)
684 return -ENOMEM;
685 to_name = dentry_name(to, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if(to_name == NULL){
687 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 err = link_file(to_name, from_name);
691 kfree(from_name);
692 kfree(to_name);
693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
696int hostfs_unlink(struct inode *ino, struct dentry *dentry)
697{
698 char *file;
699 int err;
700
Jeff Dikef1adc052007-05-08 00:23:18 -0700701 if((file = inode_dentry_name(ino, dentry)) == NULL)
702 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if(append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 err = unlink_file(file);
707 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
711int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
712{
713 char *file;
714 int err;
715
Jeff Dikef1adc052007-05-08 00:23:18 -0700716 if((file = inode_dentry_name(ino, dentry)) == NULL)
717 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 err = make_symlink(file, to);
719 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700720 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
723int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
724{
725 char *file;
726 int err;
727
Jeff Dikef1adc052007-05-08 00:23:18 -0700728 if((file = inode_dentry_name(ino, dentry)) == NULL)
729 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 err = do_mkdir(file, mode);
731 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
735int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
736{
737 char *file;
738 int err;
739
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 if((file = inode_dentry_name(ino, dentry)) == NULL)
741 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 err = do_rmdir(file);
743 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700744 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
748{
749 struct inode *inode;
750 char *name;
751 int err = -ENOMEM;
752
753 inode = iget(dir->i_sb, 0);
754 if(inode == NULL)
755 goto out;
756
757 err = init_inode(inode, dentry);
758 if(err)
759 goto out_put;
760
761 err = -ENOMEM;
762 name = dentry_name(dentry, 0);
763 if(name == NULL)
764 goto out_put;
765
766 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800767 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if(err)
769 goto out_free;
770
771 err = read_name(inode, name);
772 kfree(name);
773 if(err)
774 goto out_put;
775
776 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700777 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
779 out_free:
780 kfree(name);
781 out_put:
782 iput(inode);
783 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700784 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
787int hostfs_rename(struct inode *from_ino, struct dentry *from,
788 struct inode *to_ino, struct dentry *to)
789{
790 char *from_name, *to_name;
791 int err;
792
793 if((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700794 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if((to_name = inode_dentry_name(to_ino, to)) == NULL){
796 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700797 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799 err = rename_file(from_name, to_name);
800 kfree(from_name);
801 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700802 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803}
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
806{
807 char *name;
808 int r = 0, w = 0, x = 0, err;
809
810 if (desired & MAY_READ) r = 1;
811 if (desired & MAY_WRITE) w = 1;
812 if (desired & MAY_EXEC) x = 1;
813 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700814 if (name == NULL)
815 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
818 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
819 err = 0;
820 else
821 err = access_file(name, r, w, x);
822 kfree(name);
823 if(!err)
824 err = generic_permission(ino, desired, NULL);
825 return err;
826}
827
828int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
829{
830 struct hostfs_iattr attrs;
831 char *name;
832 int err;
833
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700834 int fd = HOSTFS_I(dentry->d_inode)->fd;
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 err = inode_change_ok(dentry->d_inode, attr);
837 if (err)
838 return err;
839
840 if(append)
841 attr->ia_valid &= ~ATTR_SIZE;
842
843 attrs.ia_valid = 0;
844 if(attr->ia_valid & ATTR_MODE){
845 attrs.ia_valid |= HOSTFS_ATTR_MODE;
846 attrs.ia_mode = attr->ia_mode;
847 }
848 if(attr->ia_valid & ATTR_UID){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 attrs.ia_valid |= HOSTFS_ATTR_UID;
850 attrs.ia_uid = attr->ia_uid;
851 }
852 if(attr->ia_valid & ATTR_GID){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 attrs.ia_valid |= HOSTFS_ATTR_GID;
854 attrs.ia_gid = attr->ia_gid;
855 }
856 if(attr->ia_valid & ATTR_SIZE){
857 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
858 attrs.ia_size = attr->ia_size;
859 }
860 if(attr->ia_valid & ATTR_ATIME){
861 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
862 attrs.ia_atime = attr->ia_atime;
863 }
864 if(attr->ia_valid & ATTR_MTIME){
865 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
866 attrs.ia_mtime = attr->ia_mtime;
867 }
868 if(attr->ia_valid & ATTR_CTIME){
869 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
870 attrs.ia_ctime = attr->ia_ctime;
871 }
872 if(attr->ia_valid & ATTR_ATIME_SET){
873 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
874 }
875 if(attr->ia_valid & ATTR_MTIME_SET){
876 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
877 }
878 name = dentry_name(dentry, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700879 if(name == NULL)
880 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700881 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 kfree(name);
883 if(err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700884 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Jeff Dikef1adc052007-05-08 00:23:18 -0700886 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887}
888
889int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
890 struct kstat *stat)
891{
892 generic_fillattr(dentry->d_inode, stat);
Jeff Dikef1adc052007-05-08 00:23:18 -0700893 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800896static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 .create = hostfs_create,
898 .link = hostfs_link,
899 .unlink = hostfs_unlink,
900 .symlink = hostfs_symlink,
901 .mkdir = hostfs_mkdir,
902 .rmdir = hostfs_rmdir,
903 .mknod = hostfs_mknod,
904 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 .permission = hostfs_permission,
906 .setattr = hostfs_setattr,
907 .getattr = hostfs_getattr,
908};
909
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800910static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 .create = hostfs_create,
912 .lookup = hostfs_lookup,
913 .link = hostfs_link,
914 .unlink = hostfs_unlink,
915 .symlink = hostfs_symlink,
916 .mkdir = hostfs_mkdir,
917 .rmdir = hostfs_rmdir,
918 .mknod = hostfs_mknod,
919 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 .permission = hostfs_permission,
921 .setattr = hostfs_setattr,
922 .getattr = hostfs_getattr,
923};
924
925int hostfs_link_readpage(struct file *file, struct page *page)
926{
927 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 int err;
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 buffer = kmap(page);
931 name = inode_name(page->mapping->host, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700932 if(name == NULL)
933 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
935 kfree(name);
936 if(err == PAGE_CACHE_SIZE)
937 err = -E2BIG;
938 else if(err > 0){
939 flush_dcache_page(page);
940 SetPageUptodate(page);
941 if (PageError(page)) ClearPageError(page);
942 err = 0;
943 }
944 kunmap(page);
945 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700946 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947}
948
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700949static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 .readpage = hostfs_link_readpage,
951};
952
953static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
954{
955 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700956 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 int err;
958
959 sb->s_blocksize = 1024;
960 sb->s_blocksize_bits = 10;
961 sb->s_magic = HOSTFS_SUPER_MAGIC;
962 sb->s_op = &hostfs_sbops;
963
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800964 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700965 if (req_root == NULL)
966 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700969 host_root_path = kmalloc(strlen(root_ino) + 1
970 + strlen(req_root) + 1, GFP_KERNEL);
971 if(host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 goto out;
973
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700974 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 root_inode = iget(sb, 0);
977 if(root_inode == NULL)
978 goto out_free;
979
980 err = init_inode(root_inode, NULL);
981 if(err)
982 goto out_put;
983
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700984 HOSTFS_I(root_inode)->host_filename = host_root_path;
985 /* Avoid that in the error path, iput(root_inode) frees again
986 * host_root_path through hostfs_destroy_inode! */
987 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 err = -ENOMEM;
990 sb->s_root = d_alloc_root(root_inode);
991 if(sb->s_root == NULL)
992 goto out_put;
993
994 err = read_inode(root_inode);
Jeff Dike51a14112005-05-05 16:15:34 -0700995 if(err){
Jeff Dikef1adc052007-05-08 00:23:18 -0700996 /* No iput in this case because the dput does that for us */
997 dput(sb->s_root);
998 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -0800999 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -07001000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
Jeff Dikef1adc052007-05-08 00:23:18 -07001002 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Jeff Dikef1adc052007-05-08 00:23:18 -07001004out_put:
1005 iput(root_inode);
1006out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001007 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -07001008out:
1009 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
David Howells454e2392006-06-23 02:02:57 -07001012static int hostfs_read_sb(struct file_system_type *type,
1013 int flags, const char *dev_name,
1014 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{
David Howells454e2392006-06-23 02:02:57 -07001016 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017}
1018
1019static struct file_system_type hostfs_type = {
1020 .owner = THIS_MODULE,
1021 .name = "hostfs",
1022 .get_sb = hostfs_read_sb,
1023 .kill_sb = kill_anon_super,
1024 .fs_flags = 0,
1025};
1026
1027static int __init init_hostfs(void)
1028{
Jeff Dikef1adc052007-05-08 00:23:18 -07001029 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030}
1031
1032static void __exit exit_hostfs(void)
1033{
1034 unregister_filesystem(&hostfs_type);
1035}
1036
1037module_init(init_hostfs)
1038module_exit(exit_hostfs)
1039MODULE_LICENSE("GPL");