blob: 5222345ddccf6525a13cd74fe801da1bde50a304 [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>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080014#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080015#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070018#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20struct hostfs_inode_info {
21 char *host_filename;
22 int fd;
23 int mode;
24 struct inode vfs_inode;
25};
26
27static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
28{
Jeff Dikef1adc052007-05-08 00:23:18 -070029 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030}
31
Josef Sipek680b0da2006-12-08 02:37:05 -080032#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34int hostfs_d_delete(struct dentry *dentry)
35{
Jeff Dikef1adc052007-05-08 00:23:18 -070036 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037}
38
39struct dentry_operations hostfs_dentry_ops = {
40 .d_delete = hostfs_d_delete,
41};
42
43/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080044static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static int append = 0;
46
47#define HOSTFS_SUPER_MAGIC 0x00c0ffee
48
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080049static const struct inode_operations hostfs_iops;
50static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070051static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#ifndef MODULE
54static int __init hostfs_args(char *options, int *add)
55{
56 char *ptr;
57
58 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070059 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070061 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 root_ino = options;
63
64 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070065 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070067 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070069 if (*options != '\0') {
70 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 append = 1;
72 else printf("hostfs_args - unsupported option - %s\n",
73 options);
74 }
75 options = ptr;
76 }
Jeff Dikef1adc052007-05-08 00:23:18 -070077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
80__uml_setup("hostfs=", hostfs_args,
81"hostfs=<root dir>,<flags>,...\n"
82" This is used to set hostfs parameters. The root directory argument\n"
83" is used to confine all hostfs mounts to within the specified directory\n"
84" tree on the host. If this isn't specified, then a user inside UML can\n"
85" mount anything on the host that's accessible to the user that's running\n"
86" it.\n"
87" The only flag currently supported is 'append', which specifies that all\n"
88" files opened by hostfs will be opened in append mode.\n\n"
89);
90#endif
91
92static char *dentry_name(struct dentry *dentry, int extra)
93{
94 struct dentry *parent;
95 char *root, *name;
96 int len;
97
98 len = 0;
99 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700100 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 len += parent->d_name.len + 1;
102 parent = parent->d_parent;
103 }
104
105 root = HOSTFS_I(parent->d_inode)->host_filename;
106 len += strlen(root);
107 name = kmalloc(len + extra + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700108 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700109 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111 name[len] = '\0';
112 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700113 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 len -= parent->d_name.len + 1;
115 name[len] = '/';
116 strncpy(&name[len + 1], parent->d_name.name,
117 parent->d_name.len);
118 parent = parent->d_parent;
119 }
120 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700121 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
124static char *inode_name(struct inode *ino, int extra)
125{
126 struct dentry *dentry;
127
128 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700129 return dentry_name(dentry, extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
132static int read_name(struct inode *ino, char *name)
133{
Jeff Dike84b3db02007-10-16 01:27:13 -0700134 /*
135 * The non-int inode fields are copied into ints by stat_file and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 * then copied into the inode because passing the actual pointers
137 * in and having them treated as int * breaks on big-endian machines
138 */
139 int err;
140 int i_mode, i_nlink, i_blksize;
141 unsigned long long i_size;
142 unsigned long long i_ino;
143 unsigned long long i_blocks;
144
145 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
146 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700147 &ino->i_ctime, &i_blksize, &i_blocks, -1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700148 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700149 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 ino->i_ino = i_ino;
152 ino->i_mode = i_mode;
153 ino->i_nlink = i_nlink;
154 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 ino->i_blocks = i_blocks;
Jeff Dikef1adc052007-05-08 00:23:18 -0700156 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157}
158
159static char *follow_link(char *link)
160{
161 int len, n;
162 char *name, *resolved, *end;
163
164 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 n = -ENOMEM;
167 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 goto out;
170
171 n = do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700172 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 break;
174 len *= 2;
175 kfree(name);
176 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700177 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 goto out_free;
179
Jeff Dike84b3db02007-10-16 01:27:13 -0700180 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700181 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700184 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700185 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
187 *(end + 1) = '\0';
188 len = strlen(link) + strlen(name) + 1;
189
190 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700191 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 n = -ENOMEM;
193 goto out_free;
194 }
195
196 sprintf(resolved, "%s%s", link, name);
197 kfree(name);
198 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700199 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 out_free:
202 kfree(name);
203 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700204 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
David Howells0a370e52008-02-07 00:15:50 -0800207static int hostfs_read_inode(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 char *name;
210 int err = 0;
211
Jeff Dike84b3db02007-10-16 01:27:13 -0700212 /*
213 * Unfortunately, we are called from iget() when we don't have a dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 * allocated yet.
215 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700216 if (list_empty(&ino->i_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 goto out;
218
219 err = -ENOMEM;
220 name = inode_name(ino, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700221 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 goto out;
223
Jeff Dike84b3db02007-10-16 01:27:13 -0700224 if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 name = follow_link(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700226 if (IS_ERR(name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 err = PTR_ERR(name);
228 goto out;
229 }
230 }
231
232 err = read_name(ino, name);
233 kfree(name);
234 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700235 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
237
David Howells0a370e52008-02-07 00:15:50 -0800238static struct inode *hostfs_iget(struct super_block *sb)
239{
240 struct inode *inode;
241 long ret;
242
243 inode = iget_locked(sb, 0);
244 if (!inode)
245 return ERR_PTR(-ENOMEM);
246 if (inode->i_state & I_NEW) {
247 ret = hostfs_read_inode(inode);
248 if (ret < 0) {
249 iget_failed(inode);
250 return ERR_PTR(ret);
251 }
252 unlock_new_inode(inode);
253 }
254 return inode;
255}
256
David Howells726c3342006-06-23 02:02:58 -0700257int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
Jeff Dike84b3db02007-10-16 01:27:13 -0700259 /*
260 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 * struct statfs still has 32-bit versions for most of these fields,
262 * so we convert them here
263 */
264 int err;
265 long long f_blocks;
266 long long f_bfree;
267 long long f_bavail;
268 long long f_files;
269 long long f_ffree;
270
David Howells726c3342006-06-23 02:02:58 -0700271 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
273 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
274 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700275 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700276 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 sf->f_blocks = f_blocks;
278 sf->f_bfree = f_bfree;
279 sf->f_bavail = f_bavail;
280 sf->f_files = f_files;
281 sf->f_ffree = f_ffree;
282 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700283 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
286static struct inode *hostfs_alloc_inode(struct super_block *sb)
287{
288 struct hostfs_inode_info *hi;
289
290 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700291 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700292 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
295 .fd = -1,
296 .mode = 0 });
297 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700298 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
301static void hostfs_delete_inode(struct inode *inode)
302{
Mark Fashehfef26652005-09-09 13:01:31 -0700303 truncate_inode_pages(&inode->i_data, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700304 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 close_file(&HOSTFS_I(inode)->fd);
306 HOSTFS_I(inode)->fd = -1;
307 }
308 clear_inode(inode);
309}
310
311static void hostfs_destroy_inode(struct inode *inode)
312{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800313 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Jeff Dike84b3db02007-10-16 01:27:13 -0700315 /*
316 * XXX: This should not happen, probably. The check is here for
317 * additional safety.
318 */
319 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 close_file(&HOSTFS_I(inode)->fd);
321 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
322 }
323
324 kfree(HOSTFS_I(inode));
325}
326
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800327static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
328{
329 struct inode *root = vfs->mnt_sb->s_root->d_inode;
330 const char *root_path = HOSTFS_I(root)->host_filename;
331 size_t offset = strlen(root_ino) + 1;
332
333 if (strlen(root_path) > offset)
334 seq_printf(seq, ",%s", root_path + offset);
335
336 return 0;
337}
338
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800339static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 .alloc_inode = hostfs_alloc_inode,
341 .drop_inode = generic_delete_inode,
342 .delete_inode = hostfs_delete_inode,
343 .destroy_inode = hostfs_destroy_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800345 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346};
347
348int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
349{
350 void *dir;
351 char *name;
352 unsigned long long next, ino;
353 int error, len;
354
Josef Sipek680b0da2006-12-08 02:37:05 -0800355 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700356 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700357 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 dir = open_dir(name, &error);
359 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700360 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700361 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700363 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 error = (*filldir)(ent, name, len, file->f_pos,
365 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700366 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 file->f_pos = next;
368 }
369 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700370 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371}
372
373int hostfs_file_open(struct inode *ino, struct file *file)
374{
375 char *name;
376 int mode = 0, r = 0, w = 0, fd;
377
378 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700379 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700380 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Jeff Dike84b3db02007-10-16 01:27:13 -0700382 /*
383 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 * so this resets things and reopens the file with the new access.
385 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700386 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 close_file(&HOSTFS_I(ino)->fd);
388 HOSTFS_I(ino)->fd = -1;
389 }
390
391 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700392 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700394 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700396 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 r = 1;
398
Josef Sipek680b0da2006-12-08 02:37:05 -0800399 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700400 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700401 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 fd = open_file(name, r, w, append);
404 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700405 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700406 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 FILE_HOSTFS_I(file)->fd = fd;
408
Jeff Dikef1adc052007-05-08 00:23:18 -0700409 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
412int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
413{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700414 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800417static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700419 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200420 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 .aio_read = generic_file_aio_read,
422 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700423 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 .mmap = generic_file_mmap,
425 .open = hostfs_file_open,
426 .release = NULL,
427 .fsync = hostfs_fsync,
428};
429
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800430static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 .llseek = generic_file_llseek,
432 .readdir = hostfs_readdir,
433 .read = generic_read_dir,
434};
435
436int hostfs_writepage(struct page *page, struct writeback_control *wbc)
437{
438 struct address_space *mapping = page->mapping;
439 struct inode *inode = mapping->host;
440 char *buffer;
441 unsigned long long base;
442 int count = PAGE_CACHE_SIZE;
443 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
444 int err;
445
446 if (page->index >= end_index)
447 count = inode->i_size & (PAGE_CACHE_SIZE-1);
448
449 buffer = kmap(page);
450 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
451
452 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700453 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 ClearPageUptodate(page);
455 goto out;
456 }
457
458 if (base > inode->i_size)
459 inode->i_size = base;
460
461 if (PageError(page))
462 ClearPageError(page);
463 err = 0;
464
465 out:
466 kunmap(page);
467
468 unlock_page(page);
469 return err;
470}
471
472int hostfs_readpage(struct file *file, struct page *page)
473{
474 char *buffer;
475 long long start;
476 int err = 0;
477
478 start = (long long) page->index << PAGE_CACHE_SHIFT;
479 buffer = kmap(page);
480 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
481 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700482 if (err < 0)
483 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
485 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
486
487 flush_dcache_page(page);
488 SetPageUptodate(page);
489 if (PageError(page)) ClearPageError(page);
490 err = 0;
491 out:
492 kunmap(page);
493 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700494 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Nick Pigginae361ff2007-10-16 01:25:17 -0700497int hostfs_write_begin(struct file *file, struct address_space *mapping,
498 loff_t pos, unsigned len, unsigned flags,
499 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
Nick Pigginae361ff2007-10-16 01:25:17 -0700501 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Nick Pigginae361ff2007-10-16 01:25:17 -0700503 *pagep = __grab_cache_page(mapping, index);
504 if (!*pagep)
505 return -ENOMEM;
506 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507}
508
Nick Pigginae361ff2007-10-16 01:25:17 -0700509int hostfs_write_end(struct file *file, struct address_space *mapping,
510 loff_t pos, unsigned len, unsigned copied,
511 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700514 void *buffer;
515 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
516 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700519 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700521
522 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
523 SetPageUptodate(page);
524
Jeff Dike84b3db02007-10-16 01:27:13 -0700525 /*
526 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700527 * i_size against the last byte written.
528 */
529 if (err > 0 && (pos > inode->i_size))
530 inode->i_size = pos;
531 unlock_page(page);
532 page_cache_release(page);
533
Jeff Dikef1adc052007-05-08 00:23:18 -0700534 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535}
536
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700537static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 .writepage = hostfs_writepage,
539 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700540 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700541 .write_begin = hostfs_write_begin,
542 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543};
544
545static int init_inode(struct inode *inode, struct dentry *dentry)
546{
547 char *name;
548 int type, err = -ENOMEM;
549 int maj, min;
550 dev_t rdev = 0;
551
Jeff Dike84b3db02007-10-16 01:27:13 -0700552 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700554 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 goto out;
556 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700557 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 rdev = MKDEV(maj, min);
559 kfree(name);
560 }
561 else type = OS_TYPE_DIR;
562
563 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700564 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700566 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 inode->i_op = &hostfs_dir_iops;
568 else inode->i_op = &hostfs_iops;
569
Jeff Dike84b3db02007-10-16 01:27:13 -0700570 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 else inode->i_fop = &hostfs_file_fops;
572
Jeff Dike84b3db02007-10-16 01:27:13 -0700573 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 inode->i_mapping->a_ops = &hostfs_link_aops;
575 else inode->i_mapping->a_ops = &hostfs_aops;
576
577 switch (type) {
578 case OS_TYPE_CHARDEV:
579 init_special_inode(inode, S_IFCHR, rdev);
580 break;
581 case OS_TYPE_BLOCKDEV:
582 init_special_inode(inode, S_IFBLK, rdev);
583 break;
584 case OS_TYPE_FIFO:
585 init_special_inode(inode, S_IFIFO, 0);
586 break;
587 case OS_TYPE_SOCK:
588 init_special_inode(inode, S_IFSOCK, 0);
589 break;
590 }
591 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700592 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
595int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700596 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 struct inode *inode;
599 char *name;
600 int error, fd;
601
David Howells0a370e52008-02-07 00:15:50 -0800602 inode = hostfs_iget(dir->i_sb);
603 if (IS_ERR(inode)) {
604 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700605 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700609 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto out_put;
611
612 error = -ENOMEM;
613 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700614 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 goto out_put;
616
617 fd = file_create(name,
618 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
619 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
620 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700621 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 error = fd;
623 else error = read_name(inode, name);
624
625 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700626 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 goto out_put;
628
629 HOSTFS_I(inode)->fd = fd;
630 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
631 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700632 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 out_put:
635 iput(inode);
636 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638}
639
640struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
643 struct inode *inode;
644 char *name;
645 int err;
646
David Howells0a370e52008-02-07 00:15:50 -0800647 inode = hostfs_iget(ino->i_sb);
648 if (IS_ERR(inode)) {
649 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700654 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 goto out_put;
656
657 err = -ENOMEM;
658 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700659 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 goto out_put;
661
662 err = read_name(inode, name);
663 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700664 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 iput(inode);
666 inode = NULL;
667 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700668 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 goto out_put;
670
671 d_add(dentry, inode);
672 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
675 out_put:
676 iput(inode);
677 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
682{
Jeff Dikef1adc052007-05-08 00:23:18 -0700683 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 int len;
685
686 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700687 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return NULL;
689 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
696int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
697{
Jeff Dikef1adc052007-05-08 00:23:18 -0700698 char *from_name, *to_name;
699 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Jeff Dike84b3db02007-10-16 01:27:13 -0700701 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700702 return -ENOMEM;
703 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700704 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700706 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 err = link_file(to_name, from_name);
709 kfree(from_name);
710 kfree(to_name);
711 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
714int hostfs_unlink(struct inode *ino, struct dentry *dentry)
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;
Jeff Dike84b3db02007-10-16 01:27:13 -0700721 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700722 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 err = unlink_file(file);
725 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700726 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
729int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
730{
731 char *file;
732 int err;
733
Jeff Dike84b3db02007-10-16 01:27:13 -0700734 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700735 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 err = make_symlink(file, to);
737 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700738 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
742{
743 char *file;
744 int err;
745
Jeff Dike84b3db02007-10-16 01:27:13 -0700746 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700747 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 err = do_mkdir(file, mode);
749 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700750 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751}
752
753int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
754{
755 char *file;
756 int err;
757
Jeff Dike84b3db02007-10-16 01:27:13 -0700758 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700759 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 err = do_rmdir(file);
761 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700762 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
765int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
766{
767 struct inode *inode;
768 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800769 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
David Howells0a370e52008-02-07 00:15:50 -0800771 inode = hostfs_iget(dir->i_sb);
772 if (IS_ERR(inode)) {
773 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700778 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 goto out_put;
780
781 err = -ENOMEM;
782 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700783 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 goto out_put;
785
786 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800787 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700788 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 goto out_free;
790
791 err = read_name(inode, name);
792 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700793 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 goto out_put;
795
796 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700797 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 out_free:
800 kfree(name);
801 out_put:
802 iput(inode);
803 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700804 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805}
806
807int hostfs_rename(struct inode *from_ino, struct dentry *from,
808 struct inode *to_ino, struct dentry *to)
809{
810 char *from_name, *to_name;
811 int err;
812
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700814 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700817 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 err = rename_file(from_name, to_name);
820 kfree(from_name);
821 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700822 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823}
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
826{
827 char *name;
828 int r = 0, w = 0, x = 0, err;
829
830 if (desired & MAY_READ) r = 1;
831 if (desired & MAY_WRITE) w = 1;
832 if (desired & MAY_EXEC) x = 1;
833 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700834 if (name == NULL)
835 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700838 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 err = 0;
840 else
841 err = access_file(name, r, w, x);
842 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 err = generic_permission(ino, desired, NULL);
845 return err;
846}
847
848int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
849{
850 struct hostfs_iattr attrs;
851 char *name;
852 int err;
853
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700854 int fd = HOSTFS_I(dentry->d_inode)->fd;
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 err = inode_change_ok(dentry->d_inode, attr);
857 if (err)
858 return err;
859
Jeff Dike84b3db02007-10-16 01:27:13 -0700860 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 attr->ia_valid &= ~ATTR_SIZE;
862
863 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700864 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 attrs.ia_valid |= HOSTFS_ATTR_MODE;
866 attrs.ia_mode = attr->ia_mode;
867 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700868 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 attrs.ia_valid |= HOSTFS_ATTR_UID;
870 attrs.ia_uid = attr->ia_uid;
871 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700872 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 attrs.ia_valid |= HOSTFS_ATTR_GID;
874 attrs.ia_gid = attr->ia_gid;
875 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700876 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
878 attrs.ia_size = attr->ia_size;
879 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700880 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
882 attrs.ia_atime = attr->ia_atime;
883 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700884 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
886 attrs.ia_mtime = attr->ia_mtime;
887 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700888 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
890 attrs.ia_ctime = attr->ia_ctime;
891 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700892 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
894 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700895 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
897 }
898 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700899 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700900 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700901 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700903 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700904 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Jeff Dikef1adc052007-05-08 00:23:18 -0700906 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800909static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 .create = hostfs_create,
911 .link = hostfs_link,
912 .unlink = hostfs_unlink,
913 .symlink = hostfs_symlink,
914 .mkdir = hostfs_mkdir,
915 .rmdir = hostfs_rmdir,
916 .mknod = hostfs_mknod,
917 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 .permission = hostfs_permission,
919 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920};
921
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800922static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 .create = hostfs_create,
924 .lookup = hostfs_lookup,
925 .link = hostfs_link,
926 .unlink = hostfs_unlink,
927 .symlink = hostfs_symlink,
928 .mkdir = hostfs_mkdir,
929 .rmdir = hostfs_rmdir,
930 .mknod = hostfs_mknod,
931 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 .permission = hostfs_permission,
933 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934};
935
936int hostfs_link_readpage(struct file *file, struct page *page)
937{
938 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 int err;
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 buffer = kmap(page);
942 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700943 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700944 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
946 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700947 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700949 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 flush_dcache_page(page);
951 SetPageUptodate(page);
952 if (PageError(page)) ClearPageError(page);
953 err = 0;
954 }
955 kunmap(page);
956 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700957 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958}
959
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700960static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 .readpage = hostfs_link_readpage,
962};
963
964static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
965{
966 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700967 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 int err;
969
970 sb->s_blocksize = 1024;
971 sb->s_blocksize_bits = 10;
972 sb->s_magic = HOSTFS_SUPER_MAGIC;
973 sb->s_op = &hostfs_sbops;
974
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800975 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700976 if (req_root == NULL)
977 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700980 host_root_path = kmalloc(strlen(root_ino) + 1
981 + strlen(req_root) + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700982 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 goto out;
984
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700985 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
David Howells0a370e52008-02-07 00:15:50 -0800987 root_inode = hostfs_iget(sb);
988 if (IS_ERR(root_inode)) {
989 err = PTR_ERR(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 goto out_free;
David Howells0a370e52008-02-07 00:15:50 -0800991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700994 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 goto out_put;
996
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700997 HOSTFS_I(root_inode)->host_filename = host_root_path;
Jeff Dike84b3db02007-10-16 01:27:13 -0700998 /*
999 * Avoid that in the error path, iput(root_inode) frees again
1000 * host_root_path through hostfs_destroy_inode!
1001 */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001002 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 err = -ENOMEM;
1005 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001006 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 goto out_put;
1008
David Howells0a370e52008-02-07 00:15:50 -08001009 err = hostfs_read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001010 if (err) {
Jeff Dikef1adc052007-05-08 00:23:18 -07001011 /* No iput in this case because the dput does that for us */
1012 dput(sb->s_root);
1013 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -08001014 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -07001015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Jeff Dikef1adc052007-05-08 00:23:18 -07001017 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Jeff Dikef1adc052007-05-08 00:23:18 -07001019out_put:
1020 iput(root_inode);
1021out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001022 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -07001023out:
1024 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025}
1026
David Howells454e2392006-06-23 02:02:57 -07001027static int hostfs_read_sb(struct file_system_type *type,
1028 int flags, const char *dev_name,
1029 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
David Howells454e2392006-06-23 02:02:57 -07001031 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032}
1033
1034static struct file_system_type hostfs_type = {
1035 .owner = THIS_MODULE,
1036 .name = "hostfs",
1037 .get_sb = hostfs_read_sb,
1038 .kill_sb = kill_anon_super,
1039 .fs_flags = 0,
1040};
1041
1042static int __init init_hostfs(void)
1043{
Jeff Dikef1adc052007-05-08 00:23:18 -07001044 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045}
1046
1047static void __exit exit_hostfs(void)
1048{
1049 unregister_filesystem(&hostfs_type);
1050}
1051
1052module_init(init_hostfs)
1053module_exit(exit_hostfs)
1054MODULE_LICENSE("GPL");