blob: 2b9b35733aacd00be2673995887521263ae66a39 [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
David Howells0a370e52008-02-07 00:15:50 -0800205static int hostfs_read_inode(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
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 Howells0a370e52008-02-07 00:15:50 -0800236static struct inode *hostfs_iget(struct super_block *sb)
237{
238 struct inode *inode;
239 long ret;
240
241 inode = iget_locked(sb, 0);
242 if (!inode)
243 return ERR_PTR(-ENOMEM);
244 if (inode->i_state & I_NEW) {
245 ret = hostfs_read_inode(inode);
246 if (ret < 0) {
247 iget_failed(inode);
248 return ERR_PTR(ret);
249 }
250 unlock_new_inode(inode);
251 }
252 return inode;
253}
254
David Howells726c3342006-06-23 02:02:58 -0700255int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
Jeff Dike84b3db02007-10-16 01:27:13 -0700257 /*
258 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 * struct statfs still has 32-bit versions for most of these fields,
260 * so we convert them here
261 */
262 int err;
263 long long f_blocks;
264 long long f_bfree;
265 long long f_bavail;
266 long long f_files;
267 long long f_ffree;
268
David Howells726c3342006-06-23 02:02:58 -0700269 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
271 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
272 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700273 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700274 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 sf->f_blocks = f_blocks;
276 sf->f_bfree = f_bfree;
277 sf->f_bavail = f_bavail;
278 sf->f_files = f_files;
279 sf->f_ffree = f_ffree;
280 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700281 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282}
283
284static struct inode *hostfs_alloc_inode(struct super_block *sb)
285{
286 struct hostfs_inode_info *hi;
287
288 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
293 .fd = -1,
294 .mode = 0 });
295 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700296 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
299static void hostfs_delete_inode(struct inode *inode)
300{
Mark Fashehfef26652005-09-09 13:01:31 -0700301 truncate_inode_pages(&inode->i_data, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700302 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 close_file(&HOSTFS_I(inode)->fd);
304 HOSTFS_I(inode)->fd = -1;
305 }
306 clear_inode(inode);
307}
308
309static void hostfs_destroy_inode(struct inode *inode)
310{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800311 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Jeff Dike84b3db02007-10-16 01:27:13 -0700313 /*
314 * XXX: This should not happen, probably. The check is here for
315 * additional safety.
316 */
317 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 close_file(&HOSTFS_I(inode)->fd);
319 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
320 }
321
322 kfree(HOSTFS_I(inode));
323}
324
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800325static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 .alloc_inode = hostfs_alloc_inode,
327 .drop_inode = generic_delete_inode,
328 .delete_inode = hostfs_delete_inode,
329 .destroy_inode = hostfs_destroy_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 .statfs = hostfs_statfs,
331};
332
333int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
334{
335 void *dir;
336 char *name;
337 unsigned long long next, ino;
338 int error, len;
339
Josef Sipek680b0da2006-12-08 02:37:05 -0800340 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700341 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700342 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 dir = open_dir(name, &error);
344 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700345 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700346 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700348 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 error = (*filldir)(ent, name, len, file->f_pos,
350 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700351 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 file->f_pos = next;
353 }
354 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700355 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
358int hostfs_file_open(struct inode *ino, struct file *file)
359{
360 char *name;
361 int mode = 0, r = 0, w = 0, fd;
362
363 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700364 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700365 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Jeff Dike84b3db02007-10-16 01:27:13 -0700367 /*
368 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 * so this resets things and reopens the file with the new access.
370 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700371 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 close_file(&HOSTFS_I(ino)->fd);
373 HOSTFS_I(ino)->fd = -1;
374 }
375
376 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700377 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700379 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700381 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 r = 1;
383
Josef Sipek680b0da2006-12-08 02:37:05 -0800384 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700385 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700386 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 fd = open_file(name, r, w, append);
389 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700390 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700391 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 FILE_HOSTFS_I(file)->fd = fd;
393
Jeff Dikef1adc052007-05-08 00:23:18 -0700394 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395}
396
397int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
398{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700399 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400}
401
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800402static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700404 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200405 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 .aio_read = generic_file_aio_read,
407 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700408 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 .mmap = generic_file_mmap,
410 .open = hostfs_file_open,
411 .release = NULL,
412 .fsync = hostfs_fsync,
413};
414
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800415static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 .llseek = generic_file_llseek,
417 .readdir = hostfs_readdir,
418 .read = generic_read_dir,
419};
420
421int hostfs_writepage(struct page *page, struct writeback_control *wbc)
422{
423 struct address_space *mapping = page->mapping;
424 struct inode *inode = mapping->host;
425 char *buffer;
426 unsigned long long base;
427 int count = PAGE_CACHE_SIZE;
428 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
429 int err;
430
431 if (page->index >= end_index)
432 count = inode->i_size & (PAGE_CACHE_SIZE-1);
433
434 buffer = kmap(page);
435 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
436
437 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700438 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 ClearPageUptodate(page);
440 goto out;
441 }
442
443 if (base > inode->i_size)
444 inode->i_size = base;
445
446 if (PageError(page))
447 ClearPageError(page);
448 err = 0;
449
450 out:
451 kunmap(page);
452
453 unlock_page(page);
454 return err;
455}
456
457int hostfs_readpage(struct file *file, struct page *page)
458{
459 char *buffer;
460 long long start;
461 int err = 0;
462
463 start = (long long) page->index << PAGE_CACHE_SHIFT;
464 buffer = kmap(page);
465 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
466 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700467 if (err < 0)
468 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
471
472 flush_dcache_page(page);
473 SetPageUptodate(page);
474 if (PageError(page)) ClearPageError(page);
475 err = 0;
476 out:
477 kunmap(page);
478 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700479 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
Nick Pigginae361ff2007-10-16 01:25:17 -0700482int hostfs_write_begin(struct file *file, struct address_space *mapping,
483 loff_t pos, unsigned len, unsigned flags,
484 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Nick Pigginae361ff2007-10-16 01:25:17 -0700486 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Nick Pigginae361ff2007-10-16 01:25:17 -0700488 *pagep = __grab_cache_page(mapping, index);
489 if (!*pagep)
490 return -ENOMEM;
491 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
Nick Pigginae361ff2007-10-16 01:25:17 -0700494int hostfs_write_end(struct file *file, struct address_space *mapping,
495 loff_t pos, unsigned len, unsigned copied,
496 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700499 void *buffer;
500 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
501 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700504 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700506
507 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
508 SetPageUptodate(page);
509
Jeff Dike84b3db02007-10-16 01:27:13 -0700510 /*
511 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700512 * i_size against the last byte written.
513 */
514 if (err > 0 && (pos > inode->i_size))
515 inode->i_size = pos;
516 unlock_page(page);
517 page_cache_release(page);
518
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,
Nick Pigginae361ff2007-10-16 01:25:17 -0700526 .write_begin = hostfs_write_begin,
527 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528};
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
Jeff Dike84b3db02007-10-16 01:27:13 -0700537 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700539 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 goto out;
541 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700542 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 rdev = MKDEV(maj, min);
544 kfree(name);
545 }
546 else type = OS_TYPE_DIR;
547
548 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700549 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700551 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 inode->i_op = &hostfs_dir_iops;
553 else inode->i_op = &hostfs_iops;
554
Jeff Dike84b3db02007-10-16 01:27:13 -0700555 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 else inode->i_fop = &hostfs_file_fops;
557
Jeff Dike84b3db02007-10-16 01:27:13 -0700558 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 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,
Jeff Dike84b3db02007-10-16 01:27:13 -0700581 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
583 struct inode *inode;
584 char *name;
585 int error, fd;
586
David Howells0a370e52008-02-07 00:15:50 -0800587 inode = hostfs_iget(dir->i_sb);
588 if (IS_ERR(inode)) {
589 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700590 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700594 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 goto out_put;
596
597 error = -ENOMEM;
598 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700599 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 goto out_put;
601
602 fd = file_create(name,
603 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
604 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
605 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700606 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 error = fd;
608 else error = read_name(inode, name);
609
610 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 HOSTFS_I(inode)->fd = fd;
615 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
616 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700617 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 out_put:
620 iput(inode);
621 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700622 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
625struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 struct inode *inode;
629 char *name;
630 int err;
631
David Howells0a370e52008-02-07 00:15:50 -0800632 inode = hostfs_iget(ino->i_sb);
633 if (IS_ERR(inode)) {
634 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700639 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 goto out_put;
641
642 err = -ENOMEM;
643 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700644 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 goto out_put;
646
647 err = read_name(inode, name);
648 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700649 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 iput(inode);
651 inode = NULL;
652 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700653 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 goto out_put;
655
656 d_add(dentry, inode);
657 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 out_put:
661 iput(inode);
662 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700663 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664}
665
666static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
667{
Jeff Dikef1adc052007-05-08 00:23:18 -0700668 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 int len;
670
671 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700672 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 return NULL;
674 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
682{
Jeff Dikef1adc052007-05-08 00:23:18 -0700683 char *from_name, *to_name;
684 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Jeff Dike84b3db02007-10-16 01:27:13 -0700686 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return -ENOMEM;
688 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700689 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 err = link_file(to_name, from_name);
694 kfree(from_name);
695 kfree(to_name);
696 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
699int hostfs_unlink(struct inode *ino, struct dentry *dentry)
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;
Jeff Dike84b3db02007-10-16 01:27:13 -0700706 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700707 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 err = unlink_file(file);
710 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700711 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
714int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
715{
716 char *file;
717 int err;
718
Jeff Dike84b3db02007-10-16 01:27:13 -0700719 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700720 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 err = make_symlink(file, to);
722 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700723 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724}
725
726int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
727{
728 char *file;
729 int err;
730
Jeff Dike84b3db02007-10-16 01:27:13 -0700731 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 err = do_mkdir(file, mode);
734 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700735 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736}
737
738int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
739{
740 char *file;
741 int err;
742
Jeff Dike84b3db02007-10-16 01:27:13 -0700743 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700744 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 err = do_rmdir(file);
746 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700747 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
750int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
751{
752 struct inode *inode;
753 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800754 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
David Howells0a370e52008-02-07 00:15:50 -0800756 inode = hostfs_iget(dir->i_sb);
757 if (IS_ERR(inode)) {
758 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700763 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 goto out_put;
765
766 err = -ENOMEM;
767 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700768 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 goto out_put;
770
771 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800772 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700773 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 goto out_free;
775
776 err = read_name(inode, name);
777 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700778 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 goto out_put;
780
781 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700782 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 out_free:
785 kfree(name);
786 out_put:
787 iput(inode);
788 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700789 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790}
791
792int hostfs_rename(struct inode *from_ino, struct dentry *from,
793 struct inode *to_ino, struct dentry *to)
794{
795 char *from_name, *to_name;
796 int err;
797
Jeff Dike84b3db02007-10-16 01:27:13 -0700798 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700799 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700800 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700802 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804 err = rename_file(from_name, to_name);
805 kfree(from_name);
806 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700807 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808}
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
811{
812 char *name;
813 int r = 0, w = 0, x = 0, err;
814
815 if (desired & MAY_READ) r = 1;
816 if (desired & MAY_WRITE) w = 1;
817 if (desired & MAY_EXEC) x = 1;
818 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700819 if (name == NULL)
820 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 err = 0;
825 else
826 err = access_file(name, r, w, x);
827 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 err = generic_permission(ino, desired, NULL);
830 return err;
831}
832
833int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
834{
835 struct hostfs_iattr attrs;
836 char *name;
837 int err;
838
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700839 int fd = HOSTFS_I(dentry->d_inode)->fd;
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 err = inode_change_ok(dentry->d_inode, attr);
842 if (err)
843 return err;
844
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 attr->ia_valid &= ~ATTR_SIZE;
847
848 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700849 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 attrs.ia_valid |= HOSTFS_ATTR_MODE;
851 attrs.ia_mode = attr->ia_mode;
852 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700853 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 attrs.ia_valid |= HOSTFS_ATTR_UID;
855 attrs.ia_uid = attr->ia_uid;
856 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700857 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 attrs.ia_valid |= HOSTFS_ATTR_GID;
859 attrs.ia_gid = attr->ia_gid;
860 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700861 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
863 attrs.ia_size = attr->ia_size;
864 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700865 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
867 attrs.ia_atime = attr->ia_atime;
868 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700869 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
871 attrs.ia_mtime = attr->ia_mtime;
872 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700873 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
875 attrs.ia_ctime = attr->ia_ctime;
876 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700877 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
879 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700880 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
882 }
883 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700884 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700885 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700886 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700888 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700889 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Jeff Dikef1adc052007-05-08 00:23:18 -0700891 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800894static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 .create = hostfs_create,
896 .link = hostfs_link,
897 .unlink = hostfs_unlink,
898 .symlink = hostfs_symlink,
899 .mkdir = hostfs_mkdir,
900 .rmdir = hostfs_rmdir,
901 .mknod = hostfs_mknod,
902 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 .permission = hostfs_permission,
904 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905};
906
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800907static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 .create = hostfs_create,
909 .lookup = hostfs_lookup,
910 .link = hostfs_link,
911 .unlink = hostfs_unlink,
912 .symlink = hostfs_symlink,
913 .mkdir = hostfs_mkdir,
914 .rmdir = hostfs_rmdir,
915 .mknod = hostfs_mknod,
916 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 .permission = hostfs_permission,
918 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919};
920
921int hostfs_link_readpage(struct file *file, struct page *page)
922{
923 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 int err;
925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 buffer = kmap(page);
927 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700928 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700929 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
931 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700932 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700934 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 flush_dcache_page(page);
936 SetPageUptodate(page);
937 if (PageError(page)) ClearPageError(page);
938 err = 0;
939 }
940 kunmap(page);
941 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700942 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943}
944
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700945static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 .readpage = hostfs_link_readpage,
947};
948
949static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
950{
951 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700952 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 int err;
954
955 sb->s_blocksize = 1024;
956 sb->s_blocksize_bits = 10;
957 sb->s_magic = HOSTFS_SUPER_MAGIC;
958 sb->s_op = &hostfs_sbops;
959
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800960 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700961 if (req_root == NULL)
962 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
964 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700965 host_root_path = kmalloc(strlen(root_ino) + 1
966 + strlen(req_root) + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700967 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 goto out;
969
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700970 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
David Howells0a370e52008-02-07 00:15:50 -0800972 root_inode = hostfs_iget(sb);
973 if (IS_ERR(root_inode)) {
974 err = PTR_ERR(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 goto out_free;
David Howells0a370e52008-02-07 00:15:50 -0800976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700979 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 goto out_put;
981
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700982 HOSTFS_I(root_inode)->host_filename = host_root_path;
Jeff Dike84b3db02007-10-16 01:27:13 -0700983 /*
984 * Avoid that in the error path, iput(root_inode) frees again
985 * host_root_path through hostfs_destroy_inode!
986 */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700987 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 err = -ENOMEM;
990 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700991 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 goto out_put;
993
David Howells0a370e52008-02-07 00:15:50 -0800994 err = hostfs_read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -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");