blob: 5c538e0ec14beeba40899ea9eb20b83b8446388e [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;
Al Viroaeb5d722008-09-02 15:28:45 -040023 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 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
WANG Congea7e7432008-11-19 15:36:46 -0800171 n = hostfs_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;
Al Viroaeb5d722008-09-02 15:28:45 -0400376 fmode_t mode = 0;
377 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700380 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700381 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Jeff Dike84b3db02007-10-16 01:27:13 -0700383 /*
384 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 * so this resets things and reopens the file with the new access.
386 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700387 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 close_file(&HOSTFS_I(ino)->fd);
389 HOSTFS_I(ino)->fd = -1;
390 }
391
392 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700393 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700395 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700397 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 r = 1;
399
Josef Sipek680b0da2006-12-08 02:37:05 -0800400 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700401 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700402 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 fd = open_file(name, r, w, append);
405 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700406 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700407 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 FILE_HOSTFS_I(file)->fd = fd;
409
Jeff Dikef1adc052007-05-08 00:23:18 -0700410 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
413int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
414{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700415 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800418static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700420 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200421 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 .aio_read = generic_file_aio_read,
423 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700424 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 .mmap = generic_file_mmap,
426 .open = hostfs_file_open,
427 .release = NULL,
428 .fsync = hostfs_fsync,
429};
430
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800431static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 .llseek = generic_file_llseek,
433 .readdir = hostfs_readdir,
434 .read = generic_read_dir,
435};
436
437int hostfs_writepage(struct page *page, struct writeback_control *wbc)
438{
439 struct address_space *mapping = page->mapping;
440 struct inode *inode = mapping->host;
441 char *buffer;
442 unsigned long long base;
443 int count = PAGE_CACHE_SIZE;
444 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
445 int err;
446
447 if (page->index >= end_index)
448 count = inode->i_size & (PAGE_CACHE_SIZE-1);
449
450 buffer = kmap(page);
451 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
452
453 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700454 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 ClearPageUptodate(page);
456 goto out;
457 }
458
459 if (base > inode->i_size)
460 inode->i_size = base;
461
462 if (PageError(page))
463 ClearPageError(page);
464 err = 0;
465
466 out:
467 kunmap(page);
468
469 unlock_page(page);
470 return err;
471}
472
473int hostfs_readpage(struct file *file, struct page *page)
474{
475 char *buffer;
476 long long start;
477 int err = 0;
478
479 start = (long long) page->index << PAGE_CACHE_SHIFT;
480 buffer = kmap(page);
481 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
482 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700483 if (err < 0)
484 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
487
488 flush_dcache_page(page);
489 SetPageUptodate(page);
490 if (PageError(page)) ClearPageError(page);
491 err = 0;
492 out:
493 kunmap(page);
494 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700495 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
Nick Pigginae361ff2007-10-16 01:25:17 -0700498int hostfs_write_begin(struct file *file, struct address_space *mapping,
499 loff_t pos, unsigned len, unsigned flags,
500 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Nick Pigginae361ff2007-10-16 01:25:17 -0700502 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Nick Piggin54566b22009-01-04 12:00:53 -0800504 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700505 if (!*pagep)
506 return -ENOMEM;
507 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
Nick Pigginae361ff2007-10-16 01:25:17 -0700510int hostfs_write_end(struct file *file, struct address_space *mapping,
511 loff_t pos, unsigned len, unsigned copied,
512 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700515 void *buffer;
516 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
517 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700520 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700522
523 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
524 SetPageUptodate(page);
525
Jeff Dike84b3db02007-10-16 01:27:13 -0700526 /*
527 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700528 * i_size against the last byte written.
529 */
530 if (err > 0 && (pos > inode->i_size))
531 inode->i_size = pos;
532 unlock_page(page);
533 page_cache_release(page);
534
Jeff Dikef1adc052007-05-08 00:23:18 -0700535 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536}
537
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700538static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 .writepage = hostfs_writepage,
540 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700541 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700542 .write_begin = hostfs_write_begin,
543 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544};
545
546static int init_inode(struct inode *inode, struct dentry *dentry)
547{
548 char *name;
549 int type, err = -ENOMEM;
550 int maj, min;
551 dev_t rdev = 0;
552
Jeff Dike84b3db02007-10-16 01:27:13 -0700553 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700555 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 goto out;
557 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700558 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 rdev = MKDEV(maj, min);
560 kfree(name);
561 }
562 else type = OS_TYPE_DIR;
563
564 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700567 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 inode->i_op = &hostfs_dir_iops;
569 else inode->i_op = &hostfs_iops;
570
Jeff Dike84b3db02007-10-16 01:27:13 -0700571 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 else inode->i_fop = &hostfs_file_fops;
573
Jeff Dike84b3db02007-10-16 01:27:13 -0700574 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 inode->i_mapping->a_ops = &hostfs_link_aops;
576 else inode->i_mapping->a_ops = &hostfs_aops;
577
578 switch (type) {
579 case OS_TYPE_CHARDEV:
580 init_special_inode(inode, S_IFCHR, rdev);
581 break;
582 case OS_TYPE_BLOCKDEV:
583 init_special_inode(inode, S_IFBLK, rdev);
584 break;
585 case OS_TYPE_FIFO:
586 init_special_inode(inode, S_IFIFO, 0);
587 break;
588 case OS_TYPE_SOCK:
589 init_special_inode(inode, S_IFSOCK, 0);
590 break;
591 }
592 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700593 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
596int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700597 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 struct inode *inode;
600 char *name;
601 int error, fd;
602
David Howells0a370e52008-02-07 00:15:50 -0800603 inode = hostfs_iget(dir->i_sb);
604 if (IS_ERR(inode)) {
605 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700606 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700610 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 goto out_put;
612
613 error = -ENOMEM;
614 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700615 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 goto out_put;
617
618 fd = file_create(name,
619 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
620 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
621 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700622 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 error = fd;
624 else error = read_name(inode, name);
625
626 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700627 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 goto out_put;
629
630 HOSTFS_I(inode)->fd = fd;
631 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
632 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 out_put:
636 iput(inode);
637 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700638 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
641struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700642 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643{
644 struct inode *inode;
645 char *name;
646 int err;
647
David Howells0a370e52008-02-07 00:15:50 -0800648 inode = hostfs_iget(ino->i_sb);
649 if (IS_ERR(inode)) {
650 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700655 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 goto out_put;
657
658 err = -ENOMEM;
659 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700660 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 goto out_put;
662
663 err = read_name(inode, name);
664 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700665 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 iput(inode);
667 inode = NULL;
668 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700669 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 goto out_put;
671
672 d_add(dentry, inode);
673 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700674 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 out_put:
677 iput(inode);
678 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700679 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
683{
Jeff Dikef1adc052007-05-08 00:23:18 -0700684 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 int len;
686
687 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700688 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700689 return NULL;
690 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700692 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700694 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
697int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
698{
Jeff Dikef1adc052007-05-08 00:23:18 -0700699 char *from_name, *to_name;
700 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Jeff Dike84b3db02007-10-16 01:27:13 -0700702 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700703 return -ENOMEM;
704 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700705 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700707 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700709 err = link_file(to_name, from_name);
710 kfree(from_name);
711 kfree(to_name);
712 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
715int hostfs_unlink(struct inode *ino, struct dentry *dentry)
716{
717 char *file;
718 int err;
719
Jeff Dike84b3db02007-10-16 01:27:13 -0700720 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700721 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700722 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700723 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 err = unlink_file(file);
726 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700727 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
729
730int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
731{
732 char *file;
733 int err;
734
Jeff Dike84b3db02007-10-16 01:27:13 -0700735 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700736 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 err = make_symlink(file, to);
738 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700739 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740}
741
742int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
743{
744 char *file;
745 int err;
746
Jeff Dike84b3db02007-10-16 01:27:13 -0700747 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 err = do_mkdir(file, mode);
750 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700751 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
754int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
755{
756 char *file;
757 int err;
758
Jeff Dike84b3db02007-10-16 01:27:13 -0700759 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700760 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 err = do_rmdir(file);
762 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700763 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764}
765
766int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
767{
768 struct inode *inode;
769 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800770 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
David Howells0a370e52008-02-07 00:15:50 -0800772 inode = hostfs_iget(dir->i_sb);
773 if (IS_ERR(inode)) {
774 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700779 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 goto out_put;
781
782 err = -ENOMEM;
783 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700784 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 goto out_put;
786
787 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800788 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 goto out_free;
791
792 err = read_name(inode, name);
793 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 goto out_put;
796
797 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700798 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 out_free:
801 kfree(name);
802 out_put:
803 iput(inode);
804 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700805 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806}
807
808int hostfs_rename(struct inode *from_ino, struct dentry *from,
809 struct inode *to_ino, struct dentry *to)
810{
811 char *from_name, *to_name;
812 int err;
813
Jeff Dike84b3db02007-10-16 01:27:13 -0700814 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700815 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700818 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 }
820 err = rename_file(from_name, to_name);
821 kfree(from_name);
822 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700823 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
Al Viroe6305c42008-07-15 21:03:57 -0400826int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 char *name;
829 int r = 0, w = 0, x = 0, err;
830
831 if (desired & MAY_READ) r = 1;
832 if (desired & MAY_WRITE) w = 1;
833 if (desired & MAY_EXEC) x = 1;
834 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700835 if (name == NULL)
836 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 err = 0;
841 else
842 err = access_file(name, r, w, x);
843 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700844 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 err = generic_permission(ino, desired, NULL);
846 return err;
847}
848
849int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
850{
851 struct hostfs_iattr attrs;
852 char *name;
853 int err;
854
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700855 int fd = HOSTFS_I(dentry->d_inode)->fd;
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 err = inode_change_ok(dentry->d_inode, attr);
858 if (err)
859 return err;
860
Jeff Dike84b3db02007-10-16 01:27:13 -0700861 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 attr->ia_valid &= ~ATTR_SIZE;
863
864 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700865 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 attrs.ia_valid |= HOSTFS_ATTR_MODE;
867 attrs.ia_mode = attr->ia_mode;
868 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700869 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 attrs.ia_valid |= HOSTFS_ATTR_UID;
871 attrs.ia_uid = attr->ia_uid;
872 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700873 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 attrs.ia_valid |= HOSTFS_ATTR_GID;
875 attrs.ia_gid = attr->ia_gid;
876 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700877 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
879 attrs.ia_size = attr->ia_size;
880 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700881 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
883 attrs.ia_atime = attr->ia_atime;
884 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700885 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
887 attrs.ia_mtime = attr->ia_mtime;
888 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700889 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
891 attrs.ia_ctime = attr->ia_ctime;
892 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700893 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
895 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700896 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
898 }
899 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700900 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700901 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700902 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700904 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700905 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Jeff Dikef1adc052007-05-08 00:23:18 -0700907 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908}
909
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800910static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 .create = hostfs_create,
912 .link = hostfs_link,
913 .unlink = hostfs_unlink,
914 .symlink = hostfs_symlink,
915 .mkdir = hostfs_mkdir,
916 .rmdir = hostfs_rmdir,
917 .mknod = hostfs_mknod,
918 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 .permission = hostfs_permission,
920 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921};
922
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800923static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 .create = hostfs_create,
925 .lookup = hostfs_lookup,
926 .link = hostfs_link,
927 .unlink = hostfs_unlink,
928 .symlink = hostfs_symlink,
929 .mkdir = hostfs_mkdir,
930 .rmdir = hostfs_rmdir,
931 .mknod = hostfs_mknod,
932 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 .permission = hostfs_permission,
934 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935};
936
937int hostfs_link_readpage(struct file *file, struct page *page)
938{
939 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 int err;
941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 buffer = kmap(page);
943 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700944 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700945 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800946 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700948 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700950 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 flush_dcache_page(page);
952 SetPageUptodate(page);
953 if (PageError(page)) ClearPageError(page);
954 err = 0;
955 }
956 kunmap(page);
957 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700958 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700961static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 .readpage = hostfs_link_readpage,
963};
964
965static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
966{
967 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700968 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 int err;
970
971 sb->s_blocksize = 1024;
972 sb->s_blocksize_bits = 10;
973 sb->s_magic = HOSTFS_SUPER_MAGIC;
974 sb->s_op = &hostfs_sbops;
975
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800976 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700977 if (req_root == NULL)
978 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700981 host_root_path = kmalloc(strlen(root_ino) + 1
982 + strlen(req_root) + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700983 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 goto out;
985
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700986 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
David Howells0a370e52008-02-07 00:15:50 -0800988 root_inode = hostfs_iget(sb);
989 if (IS_ERR(root_inode)) {
990 err = PTR_ERR(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 goto out_free;
David Howells0a370e52008-02-07 00:15:50 -0800992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700995 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 goto out_put;
997
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700998 HOSTFS_I(root_inode)->host_filename = host_root_path;
Jeff Dike84b3db02007-10-16 01:27:13 -0700999 /*
1000 * Avoid that in the error path, iput(root_inode) frees again
1001 * host_root_path through hostfs_destroy_inode!
1002 */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001003 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 err = -ENOMEM;
1006 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001007 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 goto out_put;
1009
David Howells0a370e52008-02-07 00:15:50 -08001010 err = hostfs_read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001011 if (err) {
Jeff Dikef1adc052007-05-08 00:23:18 -07001012 /* No iput in this case because the dput does that for us */
1013 dput(sb->s_root);
1014 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -08001015 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -07001016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Jeff Dikef1adc052007-05-08 00:23:18 -07001018 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Jeff Dikef1adc052007-05-08 00:23:18 -07001020out_put:
1021 iput(root_inode);
1022out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001023 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -07001024out:
1025 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026}
1027
David Howells454e2392006-06-23 02:02:57 -07001028static int hostfs_read_sb(struct file_system_type *type,
1029 int flags, const char *dev_name,
1030 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031{
David Howells454e2392006-06-23 02:02:57 -07001032 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
1035static struct file_system_type hostfs_type = {
1036 .owner = THIS_MODULE,
1037 .name = "hostfs",
1038 .get_sb = hostfs_read_sb,
1039 .kill_sb = kill_anon_super,
1040 .fs_flags = 0,
1041};
1042
1043static int __init init_hostfs(void)
1044{
Jeff Dikef1adc052007-05-08 00:23:18 -07001045 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046}
1047
1048static void __exit exit_hostfs(void)
1049{
1050 unregister_filesystem(&hostfs_type);
1051}
1052
1053module_init(init_hostfs)
1054module_exit(exit_hostfs)
1055MODULE_LICENSE("GPL");