blob: 8966b050196e33b2f717fd687dd45df9d58c48bd [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
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070011#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/statfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070016#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
18struct hostfs_inode_info {
19 char *host_filename;
20 int fd;
21 int mode;
22 struct inode vfs_inode;
23};
24
25static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
26{
Jeff Dikef1adc052007-05-08 00:23:18 -070027 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028}
29
Josef Sipek680b0da2006-12-08 02:37:05 -080030#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32int hostfs_d_delete(struct dentry *dentry)
33{
Jeff Dikef1adc052007-05-08 00:23:18 -070034 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035}
36
37struct dentry_operations hostfs_dentry_ops = {
38 .d_delete = hostfs_d_delete,
39};
40
41/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080042static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070043static int append = 0;
44
45#define HOSTFS_SUPER_MAGIC 0x00c0ffee
46
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080047static const struct inode_operations hostfs_iops;
48static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070049static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#ifndef MODULE
52static int __init hostfs_args(char *options, int *add)
53{
54 char *ptr;
55
56 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070057 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070059 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 root_ino = options;
61
62 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070063 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070065 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070067 if (*options != '\0') {
68 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 append = 1;
70 else printf("hostfs_args - unsupported option - %s\n",
71 options);
72 }
73 options = ptr;
74 }
Jeff Dikef1adc052007-05-08 00:23:18 -070075 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076}
77
78__uml_setup("hostfs=", hostfs_args,
79"hostfs=<root dir>,<flags>,...\n"
80" This is used to set hostfs parameters. The root directory argument\n"
81" is used to confine all hostfs mounts to within the specified directory\n"
82" tree on the host. If this isn't specified, then a user inside UML can\n"
83" mount anything on the host that's accessible to the user that's running\n"
84" it.\n"
85" The only flag currently supported is 'append', which specifies that all\n"
86" files opened by hostfs will be opened in append mode.\n\n"
87);
88#endif
89
90static char *dentry_name(struct dentry *dentry, int extra)
91{
92 struct dentry *parent;
93 char *root, *name;
94 int len;
95
96 len = 0;
97 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -070098 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 len += parent->d_name.len + 1;
100 parent = parent->d_parent;
101 }
102
103 root = HOSTFS_I(parent->d_inode)->host_filename;
104 len += strlen(root);
105 name = kmalloc(len + extra + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700106 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700107 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109 name[len] = '\0';
110 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700111 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 len -= parent->d_name.len + 1;
113 name[len] = '/';
114 strncpy(&name[len + 1], parent->d_name.name,
115 parent->d_name.len);
116 parent = parent->d_parent;
117 }
118 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700119 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120}
121
122static char *inode_name(struct inode *ino, int extra)
123{
124 struct dentry *dentry;
125
126 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700127 return dentry_name(dentry, extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
129
130static int read_name(struct inode *ino, char *name)
131{
Jeff Dike84b3db02007-10-16 01:27:13 -0700132 /*
133 * The non-int inode fields are copied into ints by stat_file and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 * then copied into the inode because passing the actual pointers
135 * in and having them treated as int * breaks on big-endian machines
136 */
137 int err;
138 int i_mode, i_nlink, i_blksize;
139 unsigned long long i_size;
140 unsigned long long i_ino;
141 unsigned long long i_blocks;
142
143 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
144 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700145 &ino->i_ctime, &i_blksize, &i_blocks, -1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700146 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700147 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 ino->i_ino = i_ino;
150 ino->i_mode = i_mode;
151 ino->i_nlink = i_nlink;
152 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 ino->i_blocks = i_blocks;
Jeff Dikef1adc052007-05-08 00:23:18 -0700154 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
156
157static char *follow_link(char *link)
158{
159 int len, n;
160 char *name, *resolved, *end;
161
162 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700163 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 n = -ENOMEM;
165 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700166 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 goto out;
168
169 n = do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700170 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 break;
172 len *= 2;
173 kfree(name);
174 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700175 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 goto out_free;
177
Jeff Dike84b3db02007-10-16 01:27:13 -0700178 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700179 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700182 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700183 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 *(end + 1) = '\0';
186 len = strlen(link) + strlen(name) + 1;
187
188 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700189 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 n = -ENOMEM;
191 goto out_free;
192 }
193
194 sprintf(resolved, "%s%s", link, name);
195 kfree(name);
196 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700197 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 out_free:
200 kfree(name);
201 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700202 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
205static int read_inode(struct inode *ino)
206{
207 char *name;
208 int err = 0;
209
Jeff Dike84b3db02007-10-16 01:27:13 -0700210 /*
211 * Unfortunately, we are called from iget() when we don't have a dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 * allocated yet.
213 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700214 if (list_empty(&ino->i_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 goto out;
216
217 err = -ENOMEM;
218 name = inode_name(ino, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700219 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 goto out;
221
Jeff Dike84b3db02007-10-16 01:27:13 -0700222 if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 name = follow_link(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700224 if (IS_ERR(name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 err = PTR_ERR(name);
226 goto out;
227 }
228 }
229
230 err = read_name(ino, name);
231 kfree(name);
232 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700233 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234}
235
David Howells726c3342006-06-23 02:02:58 -0700236int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Jeff Dike84b3db02007-10-16 01:27:13 -0700238 /*
239 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 * struct statfs still has 32-bit versions for most of these fields,
241 * so we convert them here
242 */
243 int err;
244 long long f_blocks;
245 long long f_bfree;
246 long long f_bavail;
247 long long f_files;
248 long long f_ffree;
249
David Howells726c3342006-06-23 02:02:58 -0700250 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
252 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
253 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700254 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700255 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 sf->f_blocks = f_blocks;
257 sf->f_bfree = f_bfree;
258 sf->f_bavail = f_bavail;
259 sf->f_files = f_files;
260 sf->f_ffree = f_ffree;
261 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700262 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263}
264
265static struct inode *hostfs_alloc_inode(struct super_block *sb)
266{
267 struct hostfs_inode_info *hi;
268
269 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700270 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700271 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
274 .fd = -1,
275 .mode = 0 });
276 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700277 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
279
280static void hostfs_delete_inode(struct inode *inode)
281{
Mark Fashehfef26652005-09-09 13:01:31 -0700282 truncate_inode_pages(&inode->i_data, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700283 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 close_file(&HOSTFS_I(inode)->fd);
285 HOSTFS_I(inode)->fd = -1;
286 }
287 clear_inode(inode);
288}
289
290static void hostfs_destroy_inode(struct inode *inode)
291{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800292 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Jeff Dike84b3db02007-10-16 01:27:13 -0700294 /*
295 * XXX: This should not happen, probably. The check is here for
296 * additional safety.
297 */
298 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 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);
Jeff Dike84b3db02007-10-16 01:27:13 -0700328 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700329 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 dir = open_dir(name, &error);
331 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700332 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700333 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700335 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 error = (*filldir)(ent, name, len, file->f_pos,
337 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700338 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 file->f_pos = next;
340 }
341 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700342 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343}
344
345int hostfs_file_open(struct inode *ino, struct file *file)
346{
347 char *name;
348 int mode = 0, r = 0, w = 0, fd;
349
350 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700351 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700352 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jeff Dike84b3db02007-10-16 01:27:13 -0700354 /*
355 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 * so this resets things and reopens the file with the new access.
357 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700358 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 close_file(&HOSTFS_I(ino)->fd);
360 HOSTFS_I(ino)->fd = -1;
361 }
362
363 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700364 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700366 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700368 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 r = 1;
370
Josef Sipek680b0da2006-12-08 02:37:05 -0800371 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700372 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700373 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 fd = open_file(name, r, w, append);
376 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700377 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700378 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 FILE_HOSTFS_I(file)->fd = fd;
380
Jeff Dikef1adc052007-05-08 00:23:18 -0700381 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
384int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
385{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700386 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800389static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700391 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200392 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 .aio_read = generic_file_aio_read,
394 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700395 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 .mmap = generic_file_mmap,
397 .open = hostfs_file_open,
398 .release = NULL,
399 .fsync = hostfs_fsync,
400};
401
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800402static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 .llseek = generic_file_llseek,
404 .readdir = hostfs_readdir,
405 .read = generic_read_dir,
406};
407
408int hostfs_writepage(struct page *page, struct writeback_control *wbc)
409{
410 struct address_space *mapping = page->mapping;
411 struct inode *inode = mapping->host;
412 char *buffer;
413 unsigned long long base;
414 int count = PAGE_CACHE_SIZE;
415 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
416 int err;
417
418 if (page->index >= end_index)
419 count = inode->i_size & (PAGE_CACHE_SIZE-1);
420
421 buffer = kmap(page);
422 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
423
424 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700425 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 ClearPageUptodate(page);
427 goto out;
428 }
429
430 if (base > inode->i_size)
431 inode->i_size = base;
432
433 if (PageError(page))
434 ClearPageError(page);
435 err = 0;
436
437 out:
438 kunmap(page);
439
440 unlock_page(page);
441 return err;
442}
443
444int hostfs_readpage(struct file *file, struct page *page)
445{
446 char *buffer;
447 long long start;
448 int err = 0;
449
450 start = (long long) page->index << PAGE_CACHE_SHIFT;
451 buffer = kmap(page);
452 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
453 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700454 if (err < 0)
455 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
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
Jeff Dike84b3db02007-10-16 01:27:13 -0700497 /*
498 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700499 * i_size against the last byte written.
500 */
501 if (err > 0 && (pos > inode->i_size))
502 inode->i_size = pos;
503 unlock_page(page);
504 page_cache_release(page);
505
Jeff Dikef1adc052007-05-08 00:23:18 -0700506 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507}
508
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700509static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 .writepage = hostfs_writepage,
511 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700512 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700513 .write_begin = hostfs_write_begin,
514 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515};
516
517static int init_inode(struct inode *inode, struct dentry *dentry)
518{
519 char *name;
520 int type, err = -ENOMEM;
521 int maj, min;
522 dev_t rdev = 0;
523
Jeff Dike84b3db02007-10-16 01:27:13 -0700524 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700526 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 goto out;
528 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700529 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 rdev = MKDEV(maj, min);
531 kfree(name);
532 }
533 else type = OS_TYPE_DIR;
534
535 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700536 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700538 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 inode->i_op = &hostfs_dir_iops;
540 else inode->i_op = &hostfs_iops;
541
Jeff Dike84b3db02007-10-16 01:27:13 -0700542 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 else inode->i_fop = &hostfs_file_fops;
544
Jeff Dike84b3db02007-10-16 01:27:13 -0700545 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 inode->i_mapping->a_ops = &hostfs_link_aops;
547 else inode->i_mapping->a_ops = &hostfs_aops;
548
549 switch (type) {
550 case OS_TYPE_CHARDEV:
551 init_special_inode(inode, S_IFCHR, rdev);
552 break;
553 case OS_TYPE_BLOCKDEV:
554 init_special_inode(inode, S_IFBLK, rdev);
555 break;
556 case OS_TYPE_FIFO:
557 init_special_inode(inode, S_IFIFO, 0);
558 break;
559 case OS_TYPE_SOCK:
560 init_special_inode(inode, S_IFSOCK, 0);
561 break;
562 }
563 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700564 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
566
567int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700568 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 struct inode *inode;
571 char *name;
572 int error, fd;
573
574 error = -ENOMEM;
575 inode = iget(dir->i_sb, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700576 if (inode == NULL)
577 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700580 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 goto out_put;
582
583 error = -ENOMEM;
584 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700585 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 goto out_put;
587
588 fd = file_create(name,
589 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
590 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
591 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700592 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 error = fd;
594 else error = read_name(inode, name);
595
596 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700597 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 goto out_put;
599
600 HOSTFS_I(inode)->fd = fd;
601 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
602 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700603 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 out_put:
606 iput(inode);
607 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700608 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609}
610
611struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700612 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
614 struct inode *inode;
615 char *name;
616 int err;
617
618 err = -ENOMEM;
619 inode = iget(ino->i_sb, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700620 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 goto out;
622
623 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700624 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 goto out_put;
626
627 err = -ENOMEM;
628 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700629 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 goto out_put;
631
632 err = read_name(inode, name);
633 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700634 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 iput(inode);
636 inode = NULL;
637 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700638 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 goto out_put;
640
641 d_add(dentry, inode);
642 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 out_put:
646 iput(inode);
647 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700648 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650
651static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
652{
Jeff Dikef1adc052007-05-08 00:23:18 -0700653 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 int len;
655
656 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700657 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return NULL;
659 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700661 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700663 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664}
665
666int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
667{
Jeff Dikef1adc052007-05-08 00:23:18 -0700668 char *from_name, *to_name;
669 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Jeff Dike84b3db02007-10-16 01:27:13 -0700671 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700672 return -ENOMEM;
673 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700674 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 err = link_file(to_name, from_name);
679 kfree(from_name);
680 kfree(to_name);
681 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
684int hostfs_unlink(struct inode *ino, struct dentry *dentry)
685{
686 char *file;
687 int err;
688
Jeff Dike84b3db02007-10-16 01:27:13 -0700689 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700691 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700692 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 err = unlink_file(file);
695 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700696 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
699int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
700{
701 char *file;
702 int err;
703
Jeff Dike84b3db02007-10-16 01:27:13 -0700704 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700705 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 err = make_symlink(file, to);
707 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
711int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
712{
713 char *file;
714 int err;
715
Jeff Dike84b3db02007-10-16 01:27:13 -0700716 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700717 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 err = do_mkdir(file, mode);
719 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700720 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
723int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
724{
725 char *file;
726 int err;
727
Jeff Dike84b3db02007-10-16 01:27:13 -0700728 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700729 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 err = do_rmdir(file);
731 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
735int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
736{
737 struct inode *inode;
738 char *name;
739 int err = -ENOMEM;
740
741 inode = iget(dir->i_sb, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700742 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 goto out;
744
745 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700746 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 goto out_put;
748
749 err = -ENOMEM;
750 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700751 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 goto out_put;
753
754 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800755 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700756 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 goto out_free;
758
759 err = read_name(inode, name);
760 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700761 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 goto out_put;
763
764 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700765 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 out_free:
768 kfree(name);
769 out_put:
770 iput(inode);
771 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700772 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773}
774
775int hostfs_rename(struct inode *from_ino, struct dentry *from,
776 struct inode *to_ino, struct dentry *to)
777{
778 char *from_name, *to_name;
779 int err;
780
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700782 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700783 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700785 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 }
787 err = rename_file(from_name, to_name);
788 kfree(from_name);
789 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700790 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
794{
795 char *name;
796 int r = 0, w = 0, x = 0, err;
797
798 if (desired & MAY_READ) r = 1;
799 if (desired & MAY_WRITE) w = 1;
800 if (desired & MAY_EXEC) x = 1;
801 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700802 if (name == NULL)
803 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700806 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 err = 0;
808 else
809 err = access_file(name, r, w, x);
810 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700811 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 err = generic_permission(ino, desired, NULL);
813 return err;
814}
815
816int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
817{
818 struct hostfs_iattr attrs;
819 char *name;
820 int err;
821
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700822 int fd = HOSTFS_I(dentry->d_inode)->fd;
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 err = inode_change_ok(dentry->d_inode, attr);
825 if (err)
826 return err;
827
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 attr->ia_valid &= ~ATTR_SIZE;
830
831 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700832 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 attrs.ia_valid |= HOSTFS_ATTR_MODE;
834 attrs.ia_mode = attr->ia_mode;
835 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700836 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 attrs.ia_valid |= HOSTFS_ATTR_UID;
838 attrs.ia_uid = attr->ia_uid;
839 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700840 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 attrs.ia_valid |= HOSTFS_ATTR_GID;
842 attrs.ia_gid = attr->ia_gid;
843 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700844 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
846 attrs.ia_size = attr->ia_size;
847 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700848 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
850 attrs.ia_atime = attr->ia_atime;
851 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700852 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
854 attrs.ia_mtime = attr->ia_mtime;
855 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700856 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
858 attrs.ia_ctime = attr->ia_ctime;
859 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700860 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
862 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700863 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
865 }
866 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700867 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700868 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700869 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700871 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700872 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Jeff Dikef1adc052007-05-08 00:23:18 -0700874 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
876
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800877static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .create = hostfs_create,
879 .link = hostfs_link,
880 .unlink = hostfs_unlink,
881 .symlink = hostfs_symlink,
882 .mkdir = hostfs_mkdir,
883 .rmdir = hostfs_rmdir,
884 .mknod = hostfs_mknod,
885 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 .permission = hostfs_permission,
887 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888};
889
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800890static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 .create = hostfs_create,
892 .lookup = hostfs_lookup,
893 .link = hostfs_link,
894 .unlink = hostfs_unlink,
895 .symlink = hostfs_symlink,
896 .mkdir = hostfs_mkdir,
897 .rmdir = hostfs_rmdir,
898 .mknod = hostfs_mknod,
899 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 .permission = hostfs_permission,
901 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902};
903
904int hostfs_link_readpage(struct file *file, struct page *page)
905{
906 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 int err;
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 buffer = kmap(page);
910 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700911 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700912 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
914 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700915 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700917 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 flush_dcache_page(page);
919 SetPageUptodate(page);
920 if (PageError(page)) ClearPageError(page);
921 err = 0;
922 }
923 kunmap(page);
924 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700925 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926}
927
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700928static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 .readpage = hostfs_link_readpage,
930};
931
932static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
933{
934 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700935 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 int err;
937
938 sb->s_blocksize = 1024;
939 sb->s_blocksize_bits = 10;
940 sb->s_magic = HOSTFS_SUPER_MAGIC;
941 sb->s_op = &hostfs_sbops;
942
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800943 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700944 if (req_root == NULL)
945 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700948 host_root_path = kmalloc(strlen(root_ino) + 1
949 + strlen(req_root) + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700950 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 goto out;
952
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700953 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 root_inode = iget(sb, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700956 if (root_inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 goto out_free;
958
959 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700960 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 goto out_put;
962
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700963 HOSTFS_I(root_inode)->host_filename = host_root_path;
Jeff Dike84b3db02007-10-16 01:27:13 -0700964 /*
965 * Avoid that in the error path, iput(root_inode) frees again
966 * host_root_path through hostfs_destroy_inode!
967 */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700968 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 err = -ENOMEM;
971 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700972 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 goto out_put;
974
975 err = read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700976 if (err) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700977 /* No iput in this case because the dput does that for us */
978 dput(sb->s_root);
979 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -0800980 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -0700981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Jeff Dikef1adc052007-05-08 00:23:18 -0700983 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Jeff Dikef1adc052007-05-08 00:23:18 -0700985out_put:
986 iput(root_inode);
987out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700988 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -0700989out:
990 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
David Howells454e2392006-06-23 02:02:57 -0700993static int hostfs_read_sb(struct file_system_type *type,
994 int flags, const char *dev_name,
995 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
David Howells454e2392006-06-23 02:02:57 -0700997 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
1000static struct file_system_type hostfs_type = {
1001 .owner = THIS_MODULE,
1002 .name = "hostfs",
1003 .get_sb = hostfs_read_sb,
1004 .kill_sb = kill_anon_super,
1005 .fs_flags = 0,
1006};
1007
1008static int __init init_hostfs(void)
1009{
Jeff Dikef1adc052007-05-08 00:23:18 -07001010 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011}
1012
1013static void __exit exit_hostfs(void)
1014{
1015 unregister_filesystem(&hostfs_type);
1016}
1017
1018module_init(init_hostfs)
1019module_exit(exit_hostfs)
1020MODULE_LICENSE("GPL");