blob: d0549cb4fb23640a79d0221262b14742b5c1a468 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070017#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19struct hostfs_inode_info {
20 char *host_filename;
21 int fd;
22 int mode;
23 struct inode vfs_inode;
24};
25
26static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
27{
Jeff Dikef1adc052007-05-08 00:23:18 -070028 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070029}
30
Josef Sipek680b0da2006-12-08 02:37:05 -080031#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33int hostfs_d_delete(struct dentry *dentry)
34{
Jeff Dikef1adc052007-05-08 00:23:18 -070035 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036}
37
38struct dentry_operations hostfs_dentry_ops = {
39 .d_delete = hostfs_d_delete,
40};
41
42/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080043static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static int append = 0;
45
46#define HOSTFS_SUPER_MAGIC 0x00c0ffee
47
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080048static const struct inode_operations hostfs_iops;
49static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070050static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#ifndef MODULE
53static int __init hostfs_args(char *options, int *add)
54{
55 char *ptr;
56
57 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070058 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 root_ino = options;
62
63 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070064 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070066 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070068 if (*options != '\0') {
69 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 append = 1;
71 else printf("hostfs_args - unsupported option - %s\n",
72 options);
73 }
74 options = ptr;
75 }
Jeff Dikef1adc052007-05-08 00:23:18 -070076 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077}
78
79__uml_setup("hostfs=", hostfs_args,
80"hostfs=<root dir>,<flags>,...\n"
81" This is used to set hostfs parameters. The root directory argument\n"
82" is used to confine all hostfs mounts to within the specified directory\n"
83" tree on the host. If this isn't specified, then a user inside UML can\n"
84" mount anything on the host that's accessible to the user that's running\n"
85" it.\n"
86" The only flag currently supported is 'append', which specifies that all\n"
87" files opened by hostfs will be opened in append mode.\n\n"
88);
89#endif
90
91static char *dentry_name(struct dentry *dentry, int extra)
92{
93 struct dentry *parent;
94 char *root, *name;
95 int len;
96
97 len = 0;
98 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -070099 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 len += parent->d_name.len + 1;
101 parent = parent->d_parent;
102 }
103
104 root = HOSTFS_I(parent->d_inode)->host_filename;
105 len += strlen(root);
106 name = kmalloc(len + extra + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700107 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700108 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
110 name[len] = '\0';
111 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700112 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 len -= parent->d_name.len + 1;
114 name[len] = '/';
115 strncpy(&name[len + 1], parent->d_name.name,
116 parent->d_name.len);
117 parent = parent->d_parent;
118 }
119 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700120 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121}
122
123static char *inode_name(struct inode *ino, int extra)
124{
125 struct dentry *dentry;
126
127 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700128 return dentry_name(dentry, extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129}
130
131static int read_name(struct inode *ino, char *name)
132{
Jeff Dike84b3db02007-10-16 01:27:13 -0700133 /*
134 * The non-int inode fields are copied into ints by stat_file and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 * then copied into the inode because passing the actual pointers
136 * in and having them treated as int * breaks on big-endian machines
137 */
138 int err;
139 int i_mode, i_nlink, i_blksize;
140 unsigned long long i_size;
141 unsigned long long i_ino;
142 unsigned long long i_blocks;
143
144 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
145 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700146 &ino->i_ctime, &i_blksize, &i_blocks, -1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700147 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700148 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 ino->i_ino = i_ino;
151 ino->i_mode = i_mode;
152 ino->i_nlink = i_nlink;
153 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 ino->i_blocks = i_blocks;
Jeff Dikef1adc052007-05-08 00:23:18 -0700155 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156}
157
158static char *follow_link(char *link)
159{
160 int len, n;
161 char *name, *resolved, *end;
162
163 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700164 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 n = -ENOMEM;
166 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700167 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 goto out;
169
170 n = do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700171 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 break;
173 len *= 2;
174 kfree(name);
175 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700176 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 goto out_free;
178
Jeff Dike84b3db02007-10-16 01:27:13 -0700179 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700180 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700183 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700184 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 *(end + 1) = '\0';
187 len = strlen(link) + strlen(name) + 1;
188
189 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700190 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 n = -ENOMEM;
192 goto out_free;
193 }
194
195 sprintf(resolved, "%s%s", link, name);
196 kfree(name);
197 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700198 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200 out_free:
201 kfree(name);
202 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700203 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
David Howells0a370e52008-02-07 00:15:50 -0800206static int hostfs_read_inode(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 char *name;
209 int err = 0;
210
Jeff Dike84b3db02007-10-16 01:27:13 -0700211 /*
212 * Unfortunately, we are called from iget() when we don't have a dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 * allocated yet.
214 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700215 if (list_empty(&ino->i_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 goto out;
217
218 err = -ENOMEM;
219 name = inode_name(ino, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700220 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 goto out;
222
Jeff Dike84b3db02007-10-16 01:27:13 -0700223 if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 name = follow_link(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700225 if (IS_ERR(name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 err = PTR_ERR(name);
227 goto out;
228 }
229 }
230
231 err = read_name(ino, name);
232 kfree(name);
233 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700234 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
236
David Howells0a370e52008-02-07 00:15:50 -0800237static struct inode *hostfs_iget(struct super_block *sb)
238{
239 struct inode *inode;
240 long ret;
241
242 inode = iget_locked(sb, 0);
243 if (!inode)
244 return ERR_PTR(-ENOMEM);
245 if (inode->i_state & I_NEW) {
246 ret = hostfs_read_inode(inode);
247 if (ret < 0) {
248 iget_failed(inode);
249 return ERR_PTR(ret);
250 }
251 unlock_new_inode(inode);
252 }
253 return inode;
254}
255
David Howells726c3342006-06-23 02:02:58 -0700256int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
Jeff Dike84b3db02007-10-16 01:27:13 -0700258 /*
259 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 * struct statfs still has 32-bit versions for most of these fields,
261 * so we convert them here
262 */
263 int err;
264 long long f_blocks;
265 long long f_bfree;
266 long long f_bavail;
267 long long f_files;
268 long long f_ffree;
269
David Howells726c3342006-06-23 02:02:58 -0700270 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
272 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
273 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700274 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700275 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 sf->f_blocks = f_blocks;
277 sf->f_bfree = f_bfree;
278 sf->f_bavail = f_bavail;
279 sf->f_files = f_files;
280 sf->f_ffree = f_ffree;
281 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700282 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283}
284
285static struct inode *hostfs_alloc_inode(struct super_block *sb)
286{
287 struct hostfs_inode_info *hi;
288
289 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700290 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700291 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
294 .fd = -1,
295 .mode = 0 });
296 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700297 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
300static void hostfs_delete_inode(struct inode *inode)
301{
Mark Fashehfef26652005-09-09 13:01:31 -0700302 truncate_inode_pages(&inode->i_data, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700303 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 close_file(&HOSTFS_I(inode)->fd);
305 HOSTFS_I(inode)->fd = -1;
306 }
307 clear_inode(inode);
308}
309
310static void hostfs_destroy_inode(struct inode *inode)
311{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800312 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Jeff Dike84b3db02007-10-16 01:27:13 -0700314 /*
315 * XXX: This should not happen, probably. The check is here for
316 * additional safety.
317 */
318 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 close_file(&HOSTFS_I(inode)->fd);
320 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
321 }
322
323 kfree(HOSTFS_I(inode));
324}
325
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800326static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
327{
328 struct inode *root = vfs->mnt_sb->s_root->d_inode;
329 const char *root_path = HOSTFS_I(root)->host_filename;
330 size_t offset = strlen(root_ino) + 1;
331
332 if (strlen(root_path) > offset)
333 seq_printf(seq, ",%s", root_path + offset);
334
335 return 0;
336}
337
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800338static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 .alloc_inode = hostfs_alloc_inode,
340 .drop_inode = generic_delete_inode,
341 .delete_inode = hostfs_delete_inode,
342 .destroy_inode = hostfs_destroy_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800344 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345};
346
347int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
348{
349 void *dir;
350 char *name;
351 unsigned long long next, ino;
352 int error, len;
353
Josef Sipek680b0da2006-12-08 02:37:05 -0800354 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700355 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700356 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 dir = open_dir(name, &error);
358 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700359 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700360 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700362 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 error = (*filldir)(ent, name, len, file->f_pos,
364 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700365 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 file->f_pos = next;
367 }
368 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700369 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
372int hostfs_file_open(struct inode *ino, struct file *file)
373{
374 char *name;
375 int mode = 0, r = 0, w = 0, fd;
376
377 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700378 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700379 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Jeff Dike84b3db02007-10-16 01:27:13 -0700381 /*
382 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 * so this resets things and reopens the file with the new access.
384 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700385 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 close_file(&HOSTFS_I(ino)->fd);
387 HOSTFS_I(ino)->fd = -1;
388 }
389
390 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700391 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700393 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700395 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 r = 1;
397
Josef Sipek680b0da2006-12-08 02:37:05 -0800398 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700399 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700400 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 fd = open_file(name, r, w, append);
403 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700404 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700405 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 FILE_HOSTFS_I(file)->fd = fd;
407
Jeff Dikef1adc052007-05-08 00:23:18 -0700408 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
411int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
412{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700413 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800416static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700418 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200419 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 .aio_read = generic_file_aio_read,
421 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700422 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 .mmap = generic_file_mmap,
424 .open = hostfs_file_open,
425 .release = NULL,
426 .fsync = hostfs_fsync,
427};
428
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800429static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 .llseek = generic_file_llseek,
431 .readdir = hostfs_readdir,
432 .read = generic_read_dir,
433};
434
435int hostfs_writepage(struct page *page, struct writeback_control *wbc)
436{
437 struct address_space *mapping = page->mapping;
438 struct inode *inode = mapping->host;
439 char *buffer;
440 unsigned long long base;
441 int count = PAGE_CACHE_SIZE;
442 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
443 int err;
444
445 if (page->index >= end_index)
446 count = inode->i_size & (PAGE_CACHE_SIZE-1);
447
448 buffer = kmap(page);
449 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
450
451 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700452 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 ClearPageUptodate(page);
454 goto out;
455 }
456
457 if (base > inode->i_size)
458 inode->i_size = base;
459
460 if (PageError(page))
461 ClearPageError(page);
462 err = 0;
463
464 out:
465 kunmap(page);
466
467 unlock_page(page);
468 return err;
469}
470
471int hostfs_readpage(struct file *file, struct page *page)
472{
473 char *buffer;
474 long long start;
475 int err = 0;
476
477 start = (long long) page->index << PAGE_CACHE_SHIFT;
478 buffer = kmap(page);
479 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
480 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700481 if (err < 0)
482 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
485
486 flush_dcache_page(page);
487 SetPageUptodate(page);
488 if (PageError(page)) ClearPageError(page);
489 err = 0;
490 out:
491 kunmap(page);
492 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700493 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
Nick Pigginae361ff2007-10-16 01:25:17 -0700496int hostfs_write_begin(struct file *file, struct address_space *mapping,
497 loff_t pos, unsigned len, unsigned flags,
498 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Nick Pigginae361ff2007-10-16 01:25:17 -0700500 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Nick Pigginae361ff2007-10-16 01:25:17 -0700502 *pagep = __grab_cache_page(mapping, index);
503 if (!*pagep)
504 return -ENOMEM;
505 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
Nick Pigginae361ff2007-10-16 01:25:17 -0700508int hostfs_write_end(struct file *file, struct address_space *mapping,
509 loff_t pos, unsigned len, unsigned copied,
510 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700513 void *buffer;
514 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
515 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700518 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700520
521 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
522 SetPageUptodate(page);
523
Jeff Dike84b3db02007-10-16 01:27:13 -0700524 /*
525 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700526 * i_size against the last byte written.
527 */
528 if (err > 0 && (pos > inode->i_size))
529 inode->i_size = pos;
530 unlock_page(page);
531 page_cache_release(page);
532
Jeff Dikef1adc052007-05-08 00:23:18 -0700533 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700536static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 .writepage = hostfs_writepage,
538 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700539 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700540 .write_begin = hostfs_write_begin,
541 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542};
543
544static int init_inode(struct inode *inode, struct dentry *dentry)
545{
546 char *name;
547 int type, err = -ENOMEM;
548 int maj, min;
549 dev_t rdev = 0;
550
Jeff Dike84b3db02007-10-16 01:27:13 -0700551 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700553 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 goto out;
555 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700556 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 rdev = MKDEV(maj, min);
558 kfree(name);
559 }
560 else type = OS_TYPE_DIR;
561
562 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700563 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 inode->i_op = &hostfs_dir_iops;
567 else inode->i_op = &hostfs_iops;
568
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 else inode->i_fop = &hostfs_file_fops;
571
Jeff Dike84b3db02007-10-16 01:27:13 -0700572 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 inode->i_mapping->a_ops = &hostfs_link_aops;
574 else inode->i_mapping->a_ops = &hostfs_aops;
575
576 switch (type) {
577 case OS_TYPE_CHARDEV:
578 init_special_inode(inode, S_IFCHR, rdev);
579 break;
580 case OS_TYPE_BLOCKDEV:
581 init_special_inode(inode, S_IFBLK, rdev);
582 break;
583 case OS_TYPE_FIFO:
584 init_special_inode(inode, S_IFIFO, 0);
585 break;
586 case OS_TYPE_SOCK:
587 init_special_inode(inode, S_IFSOCK, 0);
588 break;
589 }
590 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700591 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592}
593
594int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700595 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 struct inode *inode;
598 char *name;
599 int error, fd;
600
David Howells0a370e52008-02-07 00:15:50 -0800601 inode = hostfs_iget(dir->i_sb);
602 if (IS_ERR(inode)) {
603 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700604 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700608 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 goto out_put;
610
611 error = -ENOMEM;
612 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700613 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 goto out_put;
615
616 fd = file_create(name,
617 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
618 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
619 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700620 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 error = fd;
622 else error = read_name(inode, name);
623
624 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700625 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 goto out_put;
627
628 HOSTFS_I(inode)->fd = fd;
629 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
630 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 out_put:
634 iput(inode);
635 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700640 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
642 struct inode *inode;
643 char *name;
644 int err;
645
David Howells0a370e52008-02-07 00:15:50 -0800646 inode = hostfs_iget(ino->i_sb);
647 if (IS_ERR(inode)) {
648 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700653 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 goto out_put;
655
656 err = -ENOMEM;
657 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700658 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 goto out_put;
660
661 err = read_name(inode, name);
662 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700663 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 iput(inode);
665 inode = NULL;
666 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700667 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 goto out_put;
669
670 d_add(dentry, inode);
671 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700672 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 out_put:
675 iput(inode);
676 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700677 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
680static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
681{
Jeff Dikef1adc052007-05-08 00:23:18 -0700682 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 int len;
684
685 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700686 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return NULL;
688 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700692 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693}
694
695int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
696{
Jeff Dikef1adc052007-05-08 00:23:18 -0700697 char *from_name, *to_name;
698 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Jeff Dike84b3db02007-10-16 01:27:13 -0700700 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700701 return -ENOMEM;
702 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700703 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700705 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700707 err = link_file(to_name, from_name);
708 kfree(from_name);
709 kfree(to_name);
710 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
713int hostfs_unlink(struct inode *ino, struct dentry *dentry)
714{
715 char *file;
716 int err;
717
Jeff Dike84b3db02007-10-16 01:27:13 -0700718 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700719 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700720 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700721 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 err = unlink_file(file);
724 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700725 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726}
727
728int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
729{
730 char *file;
731 int err;
732
Jeff Dike84b3db02007-10-16 01:27:13 -0700733 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700734 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 err = make_symlink(file, to);
736 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700737 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
740int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
741{
742 char *file;
743 int err;
744
Jeff Dike84b3db02007-10-16 01:27:13 -0700745 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700746 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 err = do_mkdir(file, mode);
748 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700749 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
752int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
753{
754 char *file;
755 int err;
756
Jeff Dike84b3db02007-10-16 01:27:13 -0700757 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700758 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 err = do_rmdir(file);
760 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700761 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762}
763
764int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
765{
766 struct inode *inode;
767 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800768 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
David Howells0a370e52008-02-07 00:15:50 -0800770 inode = hostfs_iget(dir->i_sb);
771 if (IS_ERR(inode)) {
772 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700777 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 goto out_put;
779
780 err = -ENOMEM;
781 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700782 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 goto out_put;
784
785 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800786 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700787 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 goto out_free;
789
790 err = read_name(inode, name);
791 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700792 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 goto out_put;
794
795 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700796 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 out_free:
799 kfree(name);
800 out_put:
801 iput(inode);
802 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700803 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804}
805
806int hostfs_rename(struct inode *from_ino, struct dentry *from,
807 struct inode *to_ino, struct dentry *to)
808{
809 char *from_name, *to_name;
810 int err;
811
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700813 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700814 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700816 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 }
818 err = rename_file(from_name, to_name);
819 kfree(from_name);
820 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700821 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
825{
826 char *name;
827 int r = 0, w = 0, x = 0, err;
828
829 if (desired & MAY_READ) r = 1;
830 if (desired & MAY_WRITE) w = 1;
831 if (desired & MAY_EXEC) x = 1;
832 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700833 if (name == NULL)
834 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 err = 0;
839 else
840 err = access_file(name, r, w, x);
841 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700842 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 err = generic_permission(ino, desired, NULL);
844 return err;
845}
846
847int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
848{
849 struct hostfs_iattr attrs;
850 char *name;
851 int err;
852
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700853 int fd = HOSTFS_I(dentry->d_inode)->fd;
854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 err = inode_change_ok(dentry->d_inode, attr);
856 if (err)
857 return err;
858
Jeff Dike84b3db02007-10-16 01:27:13 -0700859 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 attr->ia_valid &= ~ATTR_SIZE;
861
862 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700863 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 attrs.ia_valid |= HOSTFS_ATTR_MODE;
865 attrs.ia_mode = attr->ia_mode;
866 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700867 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 attrs.ia_valid |= HOSTFS_ATTR_UID;
869 attrs.ia_uid = attr->ia_uid;
870 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700871 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 attrs.ia_valid |= HOSTFS_ATTR_GID;
873 attrs.ia_gid = attr->ia_gid;
874 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700875 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
877 attrs.ia_size = attr->ia_size;
878 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700879 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
881 attrs.ia_atime = attr->ia_atime;
882 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700883 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
885 attrs.ia_mtime = attr->ia_mtime;
886 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700887 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
889 attrs.ia_ctime = attr->ia_ctime;
890 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700891 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
893 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700894 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
896 }
897 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700898 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700899 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700900 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700902 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700903 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Jeff Dikef1adc052007-05-08 00:23:18 -0700905 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800908static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 .create = hostfs_create,
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
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800921static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 .create = hostfs_create,
923 .lookup = hostfs_lookup,
924 .link = hostfs_link,
925 .unlink = hostfs_unlink,
926 .symlink = hostfs_symlink,
927 .mkdir = hostfs_mkdir,
928 .rmdir = hostfs_rmdir,
929 .mknod = hostfs_mknod,
930 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 .permission = hostfs_permission,
932 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933};
934
935int hostfs_link_readpage(struct file *file, struct page *page)
936{
937 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 int err;
939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 buffer = kmap(page);
941 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700942 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700943 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
945 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700946 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700948 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 flush_dcache_page(page);
950 SetPageUptodate(page);
951 if (PageError(page)) ClearPageError(page);
952 err = 0;
953 }
954 kunmap(page);
955 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700956 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957}
958
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700959static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 .readpage = hostfs_link_readpage,
961};
962
963static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
964{
965 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700966 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 int err;
968
969 sb->s_blocksize = 1024;
970 sb->s_blocksize_bits = 10;
971 sb->s_magic = HOSTFS_SUPER_MAGIC;
972 sb->s_op = &hostfs_sbops;
973
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800974 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700975 if (req_root == NULL)
976 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700979 host_root_path = kmalloc(strlen(root_ino) + 1
980 + strlen(req_root) + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700981 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 goto out;
983
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700984 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
David Howells0a370e52008-02-07 00:15:50 -0800986 root_inode = hostfs_iget(sb);
987 if (IS_ERR(root_inode)) {
988 err = PTR_ERR(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 goto out_free;
David Howells0a370e52008-02-07 00:15:50 -0800990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700993 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 goto out_put;
995
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700996 HOSTFS_I(root_inode)->host_filename = host_root_path;
Jeff Dike84b3db02007-10-16 01:27:13 -0700997 /*
998 * Avoid that in the error path, iput(root_inode) frees again
999 * host_root_path through hostfs_destroy_inode!
1000 */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001001 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 err = -ENOMEM;
1004 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001005 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 goto out_put;
1007
David Howells0a370e52008-02-07 00:15:50 -08001008 err = hostfs_read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001009 if (err) {
Jeff Dikef1adc052007-05-08 00:23:18 -07001010 /* No iput in this case because the dput does that for us */
1011 dput(sb->s_root);
1012 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -08001013 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -07001014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Jeff Dikef1adc052007-05-08 00:23:18 -07001016 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Jeff Dikef1adc052007-05-08 00:23:18 -07001018out_put:
1019 iput(root_inode);
1020out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001021 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -07001022out:
1023 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024}
1025
David Howells454e2392006-06-23 02:02:57 -07001026static int hostfs_read_sb(struct file_system_type *type,
1027 int flags, const char *dev_name,
1028 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
David Howells454e2392006-06-23 02:02:57 -07001030 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031}
1032
1033static struct file_system_type hostfs_type = {
1034 .owner = THIS_MODULE,
1035 .name = "hostfs",
1036 .get_sb = hostfs_read_sb,
1037 .kill_sb = kill_anon_super,
1038 .fs_flags = 0,
1039};
1040
1041static int __init init_hostfs(void)
1042{
Jeff Dikef1adc052007-05-08 00:23:18 -07001043 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
1046static void __exit exit_hostfs(void)
1047{
1048 unregister_filesystem(&hostfs_type);
1049}
1050
1051module_init(init_hostfs)
1052module_exit(exit_hostfs)
1053MODULE_LICENSE("GPL");