blob: 8a21289d774d9d8c8dacf4e98e10002d1ba72ec5 [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,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200393 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .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
Nick Pigginae361ff2007-10-16 01:25:17 -0700469int hostfs_write_begin(struct file *file, struct address_space *mapping,
470 loff_t pos, unsigned len, unsigned flags,
471 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Nick Pigginae361ff2007-10-16 01:25:17 -0700473 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Nick Pigginae361ff2007-10-16 01:25:17 -0700475 *pagep = __grab_cache_page(mapping, index);
476 if (!*pagep)
477 return -ENOMEM;
478 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
Nick Pigginae361ff2007-10-16 01:25:17 -0700481int hostfs_write_end(struct file *file, struct address_space *mapping,
482 loff_t pos, unsigned len, unsigned copied,
483 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700486 void *buffer;
487 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
488 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700491 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700493
494 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
495 SetPageUptodate(page);
496
497 /* If err > 0, write_file has added err to pos, so we are comparing
498 * i_size against the last byte written.
499 */
500 if (err > 0 && (pos > inode->i_size))
501 inode->i_size = pos;
502 unlock_page(page);
503 page_cache_release(page);
504
Jeff Dikef1adc052007-05-08 00:23:18 -0700505 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700508static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 .writepage = hostfs_writepage,
510 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700511 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700512 .write_begin = hostfs_write_begin,
513 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514};
515
516static int init_inode(struct inode *inode, struct dentry *dentry)
517{
518 char *name;
519 int type, err = -ENOMEM;
520 int maj, min;
521 dev_t rdev = 0;
522
523 if(dentry){
524 name = dentry_name(dentry, 0);
525 if(name == NULL)
526 goto out;
527 type = file_type(name, &maj, &min);
528 /*Reencode maj and min with the kernel encoding.*/
529 rdev = MKDEV(maj, min);
530 kfree(name);
531 }
532 else type = OS_TYPE_DIR;
533
534 err = 0;
535 if(type == OS_TYPE_SYMLINK)
536 inode->i_op = &page_symlink_inode_operations;
537 else if(type == OS_TYPE_DIR)
538 inode->i_op = &hostfs_dir_iops;
539 else inode->i_op = &hostfs_iops;
540
541 if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
542 else inode->i_fop = &hostfs_file_fops;
543
544 if(type == OS_TYPE_SYMLINK)
545 inode->i_mapping->a_ops = &hostfs_link_aops;
546 else inode->i_mapping->a_ops = &hostfs_aops;
547
548 switch (type) {
549 case OS_TYPE_CHARDEV:
550 init_special_inode(inode, S_IFCHR, rdev);
551 break;
552 case OS_TYPE_BLOCKDEV:
553 init_special_inode(inode, S_IFBLK, rdev);
554 break;
555 case OS_TYPE_FIFO:
556 init_special_inode(inode, S_IFIFO, 0);
557 break;
558 case OS_TYPE_SOCK:
559 init_special_inode(inode, S_IFSOCK, 0);
560 break;
561 }
562 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700563 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
566int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
567 struct nameidata *nd)
568{
569 struct inode *inode;
570 char *name;
571 int error, fd;
572
573 error = -ENOMEM;
574 inode = iget(dir->i_sb, 0);
575 if(inode == NULL) goto out;
576
577 error = init_inode(inode, dentry);
578 if(error)
579 goto out_put;
580
581 error = -ENOMEM;
582 name = dentry_name(dentry, 0);
583 if(name == NULL)
584 goto out_put;
585
586 fd = file_create(name,
587 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
588 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
589 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
590 if(fd < 0)
591 error = fd;
592 else error = read_name(inode, name);
593
594 kfree(name);
595 if(error)
596 goto out_put;
597
598 HOSTFS_I(inode)->fd = fd;
599 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
600 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700601 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 out_put:
604 iput(inode);
605 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700606 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607}
608
609struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700610 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 struct inode *inode;
613 char *name;
614 int err;
615
616 err = -ENOMEM;
617 inode = iget(ino->i_sb, 0);
618 if(inode == NULL)
619 goto out;
620
621 err = init_inode(inode, dentry);
622 if(err)
623 goto out_put;
624
625 err = -ENOMEM;
626 name = dentry_name(dentry, 0);
627 if(name == NULL)
628 goto out_put;
629
630 err = read_name(inode, name);
631 kfree(name);
632 if(err == -ENOENT){
633 iput(inode);
634 inode = NULL;
635 }
636 else if(err)
637 goto out_put;
638
639 d_add(dentry, inode);
640 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 out_put:
644 iput(inode);
645 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
650{
Jeff Dikef1adc052007-05-08 00:23:18 -0700651 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 int len;
653
654 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 if(file == NULL)
656 return NULL;
657 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700659 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700661 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
664int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
665{
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 char *from_name, *to_name;
667 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Jeff Dikef1adc052007-05-08 00:23:18 -0700669 if((from_name = inode_dentry_name(ino, from)) == NULL)
670 return -ENOMEM;
671 to_name = dentry_name(to, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if(to_name == NULL){
673 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700674 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 err = link_file(to_name, from_name);
677 kfree(from_name);
678 kfree(to_name);
679 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682int hostfs_unlink(struct inode *ino, struct dentry *dentry)
683{
684 char *file;
685 int err;
686
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 if((file = inode_dentry_name(ino, dentry)) == NULL)
688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if(append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 err = unlink_file(file);
693 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
697int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
698{
699 char *file;
700 int err;
701
Jeff Dikef1adc052007-05-08 00:23:18 -0700702 if((file = inode_dentry_name(ino, dentry)) == NULL)
703 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 err = make_symlink(file, to);
705 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700706 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
709int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
710{
711 char *file;
712 int err;
713
Jeff Dikef1adc052007-05-08 00:23:18 -0700714 if((file = inode_dentry_name(ino, dentry)) == NULL)
715 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 err = do_mkdir(file, mode);
717 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700718 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719}
720
721int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
722{
723 char *file;
724 int err;
725
Jeff Dikef1adc052007-05-08 00:23:18 -0700726 if((file = inode_dentry_name(ino, dentry)) == NULL)
727 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 err = do_rmdir(file);
729 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700730 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
733int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
734{
735 struct inode *inode;
736 char *name;
737 int err = -ENOMEM;
738
739 inode = iget(dir->i_sb, 0);
740 if(inode == NULL)
741 goto out;
742
743 err = init_inode(inode, dentry);
744 if(err)
745 goto out_put;
746
747 err = -ENOMEM;
748 name = dentry_name(dentry, 0);
749 if(name == NULL)
750 goto out_put;
751
752 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800753 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if(err)
755 goto out_free;
756
757 err = read_name(inode, name);
758 kfree(name);
759 if(err)
760 goto out_put;
761
762 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700763 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 out_free:
766 kfree(name);
767 out_put:
768 iput(inode);
769 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700770 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771}
772
773int hostfs_rename(struct inode *from_ino, struct dentry *from,
774 struct inode *to_ino, struct dentry *to)
775{
776 char *from_name, *to_name;
777 int err;
778
779 if((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700780 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if((to_name = inode_dentry_name(to_ino, to)) == NULL){
782 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700783 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 }
785 err = rename_file(from_name, to_name);
786 kfree(from_name);
787 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700788 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
792{
793 char *name;
794 int r = 0, w = 0, x = 0, err;
795
796 if (desired & MAY_READ) r = 1;
797 if (desired & MAY_WRITE) w = 1;
798 if (desired & MAY_EXEC) x = 1;
799 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700800 if (name == NULL)
801 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
803 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
804 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
805 err = 0;
806 else
807 err = access_file(name, r, w, x);
808 kfree(name);
809 if(!err)
810 err = generic_permission(ino, desired, NULL);
811 return err;
812}
813
814int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
815{
816 struct hostfs_iattr attrs;
817 char *name;
818 int err;
819
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700820 int fd = HOSTFS_I(dentry->d_inode)->fd;
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 err = inode_change_ok(dentry->d_inode, attr);
823 if (err)
824 return err;
825
826 if(append)
827 attr->ia_valid &= ~ATTR_SIZE;
828
829 attrs.ia_valid = 0;
830 if(attr->ia_valid & ATTR_MODE){
831 attrs.ia_valid |= HOSTFS_ATTR_MODE;
832 attrs.ia_mode = attr->ia_mode;
833 }
834 if(attr->ia_valid & ATTR_UID){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 attrs.ia_valid |= HOSTFS_ATTR_UID;
836 attrs.ia_uid = attr->ia_uid;
837 }
838 if(attr->ia_valid & ATTR_GID){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 attrs.ia_valid |= HOSTFS_ATTR_GID;
840 attrs.ia_gid = attr->ia_gid;
841 }
842 if(attr->ia_valid & ATTR_SIZE){
843 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
844 attrs.ia_size = attr->ia_size;
845 }
846 if(attr->ia_valid & ATTR_ATIME){
847 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
848 attrs.ia_atime = attr->ia_atime;
849 }
850 if(attr->ia_valid & ATTR_MTIME){
851 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
852 attrs.ia_mtime = attr->ia_mtime;
853 }
854 if(attr->ia_valid & ATTR_CTIME){
855 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
856 attrs.ia_ctime = attr->ia_ctime;
857 }
858 if(attr->ia_valid & ATTR_ATIME_SET){
859 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
860 }
861 if(attr->ia_valid & ATTR_MTIME_SET){
862 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
863 }
864 name = dentry_name(dentry, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700865 if(name == NULL)
866 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700867 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 kfree(name);
869 if(err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700870 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Jeff Dikef1adc052007-05-08 00:23:18 -0700872 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
875int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
876 struct kstat *stat)
877{
878 generic_fillattr(dentry->d_inode, stat);
Jeff Dikef1adc052007-05-08 00:23:18 -0700879 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880}
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);
Jeff Dikef1adc052007-05-08 00:23:18 -0700918 if(name == NULL)
919 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
921 kfree(name);
922 if(err == PAGE_CACHE_SIZE)
923 err = -E2BIG;
924 else if(err > 0){
925 flush_dcache_page(page);
926 SetPageUptodate(page);
927 if (PageError(page)) ClearPageError(page);
928 err = 0;
929 }
930 kunmap(page);
931 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700932 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933}
934
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700935static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 .readpage = hostfs_link_readpage,
937};
938
939static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
940{
941 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700942 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 int err;
944
945 sb->s_blocksize = 1024;
946 sb->s_blocksize_bits = 10;
947 sb->s_magic = HOSTFS_SUPER_MAGIC;
948 sb->s_op = &hostfs_sbops;
949
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800950 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700951 if (req_root == NULL)
952 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700955 host_root_path = kmalloc(strlen(root_ino) + 1
956 + strlen(req_root) + 1, GFP_KERNEL);
957 if(host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 goto out;
959
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700960 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 root_inode = iget(sb, 0);
963 if(root_inode == NULL)
964 goto out_free;
965
966 err = init_inode(root_inode, NULL);
967 if(err)
968 goto out_put;
969
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700970 HOSTFS_I(root_inode)->host_filename = host_root_path;
971 /* Avoid that in the error path, iput(root_inode) frees again
972 * host_root_path through hostfs_destroy_inode! */
973 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 err = -ENOMEM;
976 sb->s_root = d_alloc_root(root_inode);
977 if(sb->s_root == NULL)
978 goto out_put;
979
980 err = read_inode(root_inode);
Jeff Dike51a14112005-05-05 16:15:34 -0700981 if(err){
Jeff Dikef1adc052007-05-08 00:23:18 -0700982 /* No iput in this case because the dput does that for us */
983 dput(sb->s_root);
984 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -0800985 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -0700986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Jeff Dikef1adc052007-05-08 00:23:18 -0700988 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Jeff Dikef1adc052007-05-08 00:23:18 -0700990out_put:
991 iput(root_inode);
992out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700993 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -0700994out:
995 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996}
997
David Howells454e2392006-06-23 02:02:57 -0700998static int hostfs_read_sb(struct file_system_type *type,
999 int flags, const char *dev_name,
1000 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
David Howells454e2392006-06-23 02:02:57 -07001002 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003}
1004
1005static struct file_system_type hostfs_type = {
1006 .owner = THIS_MODULE,
1007 .name = "hostfs",
1008 .get_sb = hostfs_read_sb,
1009 .kill_sb = kill_anon_super,
1010 .fs_flags = 0,
1011};
1012
1013static int __init init_hostfs(void)
1014{
Jeff Dikef1adc052007-05-08 00:23:18 -07001015 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016}
1017
1018static void __exit exit_hostfs(void)
1019{
1020 unregister_filesystem(&hostfs_type);
1021}
1022
1023module_init(init_hostfs)
1024module_exit(exit_hostfs)
1025MODULE_LICENSE("GPL");