blob: 3a029d8f4cf1d564f0e64c7f1ead796a193769d5 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080015#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080016#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070019#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21struct hostfs_inode_info {
22 char *host_filename;
23 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040024 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 struct inode vfs_inode;
26};
27
28static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
29{
Jeff Dikef1adc052007-05-08 00:23:18 -070030 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031}
32
Josef Sipek680b0da2006-12-08 02:37:05 -080033#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Al Viroe16404e2009-02-20 05:55:13 +000035static int hostfs_d_delete(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036{
Jeff Dikef1adc052007-05-08 00:23:18 -070037 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038}
39
Al Viroe16404e2009-02-20 05:55:13 +000040static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 .d_delete = hostfs_d_delete,
42};
43
44/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080045static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static int append = 0;
47
48#define HOSTFS_SUPER_MAGIC 0x00c0ffee
49
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080050static const struct inode_operations hostfs_iops;
51static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070052static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#ifndef MODULE
55static int __init hostfs_args(char *options, int *add)
56{
57 char *ptr;
58
59 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070062 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 root_ino = options;
64
65 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070066 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070068 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070070 if (*options != '\0') {
71 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 append = 1;
73 else printf("hostfs_args - unsupported option - %s\n",
74 options);
75 }
76 options = ptr;
77 }
Jeff Dikef1adc052007-05-08 00:23:18 -070078 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
80
81__uml_setup("hostfs=", hostfs_args,
82"hostfs=<root dir>,<flags>,...\n"
83" This is used to set hostfs parameters. The root directory argument\n"
84" is used to confine all hostfs mounts to within the specified directory\n"
85" tree on the host. If this isn't specified, then a user inside UML can\n"
86" mount anything on the host that's accessible to the user that's running\n"
87" it.\n"
88" The only flag currently supported is 'append', which specifies that all\n"
89" files opened by hostfs will be opened in append mode.\n\n"
90);
91#endif
92
93static char *dentry_name(struct dentry *dentry, int extra)
94{
95 struct dentry *parent;
96 char *root, *name;
97 int len;
98
99 len = 0;
100 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700101 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 len += parent->d_name.len + 1;
103 parent = parent->d_parent;
104 }
105
106 root = HOSTFS_I(parent->d_inode)->host_filename;
107 len += strlen(root);
108 name = kmalloc(len + extra + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700109 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700110 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112 name[len] = '\0';
113 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700114 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 len -= parent->d_name.len + 1;
116 name[len] = '/';
117 strncpy(&name[len + 1], parent->d_name.name,
118 parent->d_name.len);
119 parent = parent->d_parent;
120 }
121 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700122 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123}
124
125static char *inode_name(struct inode *ino, int extra)
126{
127 struct dentry *dentry;
128
129 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700130 return dentry_name(dentry, extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
133static int read_name(struct inode *ino, char *name)
134{
Jeff Dike84b3db02007-10-16 01:27:13 -0700135 /*
136 * The non-int inode fields are copied into ints by stat_file and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 * then copied into the inode because passing the actual pointers
138 * in and having them treated as int * breaks on big-endian machines
139 */
140 int err;
141 int i_mode, i_nlink, i_blksize;
142 unsigned long long i_size;
143 unsigned long long i_ino;
144 unsigned long long i_blocks;
145
146 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
147 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700148 &ino->i_ctime, &i_blksize, &i_blocks, -1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700149 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700150 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152 ino->i_ino = i_ino;
153 ino->i_mode = i_mode;
154 ino->i_nlink = i_nlink;
155 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 ino->i_blocks = i_blocks;
Jeff Dikef1adc052007-05-08 00:23:18 -0700157 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158}
159
160static char *follow_link(char *link)
161{
162 int len, n;
163 char *name, *resolved, *end;
164
165 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700166 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 n = -ENOMEM;
168 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700169 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 goto out;
171
WANG Congea7e7432008-11-19 15:36:46 -0800172 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700173 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 break;
175 len *= 2;
176 kfree(name);
177 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700178 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 goto out_free;
180
Jeff Dike84b3db02007-10-16 01:27:13 -0700181 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700182 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700185 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700186 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
188 *(end + 1) = '\0';
189 len = strlen(link) + strlen(name) + 1;
190
191 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700192 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 n = -ENOMEM;
194 goto out_free;
195 }
196
197 sprintf(resolved, "%s%s", link, name);
198 kfree(name);
199 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700200 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 out_free:
203 kfree(name);
204 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700205 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
David Howells0a370e52008-02-07 00:15:50 -0800208static int hostfs_read_inode(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
210 char *name;
211 int err = 0;
212
Jeff Dike84b3db02007-10-16 01:27:13 -0700213 /*
214 * Unfortunately, we are called from iget() when we don't have a dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 * allocated yet.
216 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700217 if (list_empty(&ino->i_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 goto out;
219
220 err = -ENOMEM;
221 name = inode_name(ino, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700222 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 goto out;
224
Jeff Dike84b3db02007-10-16 01:27:13 -0700225 if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 name = follow_link(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700227 if (IS_ERR(name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 err = PTR_ERR(name);
229 goto out;
230 }
231 }
232
233 err = read_name(ino, name);
234 kfree(name);
235 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700236 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
238
David Howells0a370e52008-02-07 00:15:50 -0800239static struct inode *hostfs_iget(struct super_block *sb)
240{
241 struct inode *inode;
242 long ret;
243
244 inode = iget_locked(sb, 0);
245 if (!inode)
246 return ERR_PTR(-ENOMEM);
247 if (inode->i_state & I_NEW) {
248 ret = hostfs_read_inode(inode);
249 if (ret < 0) {
250 iget_failed(inode);
251 return ERR_PTR(ret);
252 }
253 unlock_new_inode(inode);
254 }
255 return inode;
256}
257
David Howells726c3342006-06-23 02:02:58 -0700258int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
Jeff Dike84b3db02007-10-16 01:27:13 -0700260 /*
261 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 * struct statfs still has 32-bit versions for most of these fields,
263 * so we convert them here
264 */
265 int err;
266 long long f_blocks;
267 long long f_bfree;
268 long long f_bavail;
269 long long f_files;
270 long long f_ffree;
271
David Howells726c3342006-06-23 02:02:58 -0700272 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
274 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
275 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700276 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700277 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 sf->f_blocks = f_blocks;
279 sf->f_bfree = f_bfree;
280 sf->f_bavail = f_bavail;
281 sf->f_files = f_files;
282 sf->f_ffree = f_ffree;
283 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700284 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285}
286
287static struct inode *hostfs_alloc_inode(struct super_block *sb)
288{
289 struct hostfs_inode_info *hi;
290
291 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700292 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700293 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
296 .fd = -1,
297 .mode = 0 });
298 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700299 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
302static void hostfs_delete_inode(struct inode *inode)
303{
Mark Fashehfef26652005-09-09 13:01:31 -0700304 truncate_inode_pages(&inode->i_data, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700305 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 close_file(&HOSTFS_I(inode)->fd);
307 HOSTFS_I(inode)->fd = -1;
308 }
309 clear_inode(inode);
310}
311
312static void hostfs_destroy_inode(struct inode *inode)
313{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800314 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Jeff Dike84b3db02007-10-16 01:27:13 -0700316 /*
317 * XXX: This should not happen, probably. The check is here for
318 * additional safety.
319 */
320 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 close_file(&HOSTFS_I(inode)->fd);
322 printk(KERN_DEBUG "Closing host fd in .destroy_inode\n");
323 }
324
325 kfree(HOSTFS_I(inode));
326}
327
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800328static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
329{
330 struct inode *root = vfs->mnt_sb->s_root->d_inode;
331 const char *root_path = HOSTFS_I(root)->host_filename;
332 size_t offset = strlen(root_ino) + 1;
333
334 if (strlen(root_path) > offset)
335 seq_printf(seq, ",%s", root_path + offset);
336
337 return 0;
338}
339
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800340static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 .alloc_inode = hostfs_alloc_inode,
342 .drop_inode = generic_delete_inode,
343 .delete_inode = hostfs_delete_inode,
344 .destroy_inode = hostfs_destroy_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800346 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347};
348
349int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
350{
351 void *dir;
352 char *name;
353 unsigned long long next, ino;
354 int error, len;
355
Josef Sipek680b0da2006-12-08 02:37:05 -0800356 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700357 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700358 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 dir = open_dir(name, &error);
360 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700361 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700362 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700364 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 error = (*filldir)(ent, name, len, file->f_pos,
366 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700367 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 file->f_pos = next;
369 }
370 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700371 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372}
373
374int hostfs_file_open(struct inode *ino, struct file *file)
375{
376 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400377 fmode_t mode = 0;
378 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700381 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700382 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Jeff Dike84b3db02007-10-16 01:27:13 -0700384 /*
385 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 * so this resets things and reopens the file with the new access.
387 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700388 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 close_file(&HOSTFS_I(ino)->fd);
390 HOSTFS_I(ino)->fd = -1;
391 }
392
393 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700394 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700396 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700398 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 r = 1;
400
Josef Sipek680b0da2006-12-08 02:37:05 -0800401 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700402 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700403 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 fd = open_file(name, r, w, append);
406 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700407 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700408 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 FILE_HOSTFS_I(file)->fd = fd;
410
Jeff Dikef1adc052007-05-08 00:23:18 -0700411 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
414int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
415{
Paolo 'Blaisorblade' Giarrussoa2d76bd2005-07-28 21:16:15 -0700416 return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800419static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700421 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200422 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 .aio_read = generic_file_aio_read,
424 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700425 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 .mmap = generic_file_mmap,
427 .open = hostfs_file_open,
428 .release = NULL,
429 .fsync = hostfs_fsync,
430};
431
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800432static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 .llseek = generic_file_llseek,
434 .readdir = hostfs_readdir,
435 .read = generic_read_dir,
436};
437
438int hostfs_writepage(struct page *page, struct writeback_control *wbc)
439{
440 struct address_space *mapping = page->mapping;
441 struct inode *inode = mapping->host;
442 char *buffer;
443 unsigned long long base;
444 int count = PAGE_CACHE_SIZE;
445 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
446 int err;
447
448 if (page->index >= end_index)
449 count = inode->i_size & (PAGE_CACHE_SIZE-1);
450
451 buffer = kmap(page);
452 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
453
454 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700455 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 ClearPageUptodate(page);
457 goto out;
458 }
459
460 if (base > inode->i_size)
461 inode->i_size = base;
462
463 if (PageError(page))
464 ClearPageError(page);
465 err = 0;
466
467 out:
468 kunmap(page);
469
470 unlock_page(page);
471 return err;
472}
473
474int hostfs_readpage(struct file *file, struct page *page)
475{
476 char *buffer;
477 long long start;
478 int err = 0;
479
480 start = (long long) page->index << PAGE_CACHE_SHIFT;
481 buffer = kmap(page);
482 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
483 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700484 if (err < 0)
485 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
488
489 flush_dcache_page(page);
490 SetPageUptodate(page);
491 if (PageError(page)) ClearPageError(page);
492 err = 0;
493 out:
494 kunmap(page);
495 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700496 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Nick Pigginae361ff2007-10-16 01:25:17 -0700499int hostfs_write_begin(struct file *file, struct address_space *mapping,
500 loff_t pos, unsigned len, unsigned flags,
501 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Nick Pigginae361ff2007-10-16 01:25:17 -0700503 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Nick Piggin54566b22009-01-04 12:00:53 -0800505 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700506 if (!*pagep)
507 return -ENOMEM;
508 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
Nick Pigginae361ff2007-10-16 01:25:17 -0700511int hostfs_write_end(struct file *file, struct address_space *mapping,
512 loff_t pos, unsigned len, unsigned copied,
513 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700516 void *buffer;
517 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
518 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700521 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700523
524 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
525 SetPageUptodate(page);
526
Jeff Dike84b3db02007-10-16 01:27:13 -0700527 /*
528 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700529 * i_size against the last byte written.
530 */
531 if (err > 0 && (pos > inode->i_size))
532 inode->i_size = pos;
533 unlock_page(page);
534 page_cache_release(page);
535
Jeff Dikef1adc052007-05-08 00:23:18 -0700536 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700539static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 .writepage = hostfs_writepage,
541 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700542 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700543 .write_begin = hostfs_write_begin,
544 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545};
546
547static int init_inode(struct inode *inode, struct dentry *dentry)
548{
549 char *name;
550 int type, err = -ENOMEM;
551 int maj, min;
552 dev_t rdev = 0;
553
Jeff Dike84b3db02007-10-16 01:27:13 -0700554 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700556 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 goto out;
558 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700559 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 rdev = MKDEV(maj, min);
561 kfree(name);
562 }
563 else type = OS_TYPE_DIR;
564
565 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700566 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700568 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 inode->i_op = &hostfs_dir_iops;
570 else inode->i_op = &hostfs_iops;
571
Jeff Dike84b3db02007-10-16 01:27:13 -0700572 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 else inode->i_fop = &hostfs_file_fops;
574
Jeff Dike84b3db02007-10-16 01:27:13 -0700575 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 inode->i_mapping->a_ops = &hostfs_link_aops;
577 else inode->i_mapping->a_ops = &hostfs_aops;
578
579 switch (type) {
580 case OS_TYPE_CHARDEV:
581 init_special_inode(inode, S_IFCHR, rdev);
582 break;
583 case OS_TYPE_BLOCKDEV:
584 init_special_inode(inode, S_IFBLK, rdev);
585 break;
586 case OS_TYPE_FIFO:
587 init_special_inode(inode, S_IFIFO, 0);
588 break;
589 case OS_TYPE_SOCK:
590 init_special_inode(inode, S_IFSOCK, 0);
591 break;
592 }
593 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
597int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700598 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
600 struct inode *inode;
601 char *name;
602 int error, fd;
603
David Howells0a370e52008-02-07 00:15:50 -0800604 inode = hostfs_iget(dir->i_sb);
605 if (IS_ERR(inode)) {
606 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700607 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 error = -ENOMEM;
615 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700616 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 goto out_put;
618
619 fd = file_create(name,
620 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
621 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
622 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700623 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 error = fd;
625 else error = read_name(inode, name);
626
627 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700628 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 goto out_put;
630
631 HOSTFS_I(inode)->fd = fd;
632 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
633 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700634 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 out_put:
637 iput(inode);
638 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
645 struct inode *inode;
646 char *name;
647 int err;
648
David Howells0a370e52008-02-07 00:15:50 -0800649 inode = hostfs_iget(ino->i_sb);
650 if (IS_ERR(inode)) {
651 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700656 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 goto out_put;
658
659 err = -ENOMEM;
660 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700661 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 goto out_put;
663
664 err = read_name(inode, name);
665 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700666 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 iput(inode);
668 inode = NULL;
669 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700670 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 goto out_put;
672
673 d_add(dentry, inode);
674 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700675 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677 out_put:
678 iput(inode);
679 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700680 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681}
682
683static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
684{
Jeff Dikef1adc052007-05-08 00:23:18 -0700685 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 int len;
687
688 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700689 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return NULL;
691 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700695 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696}
697
698int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
699{
Jeff Dikef1adc052007-05-08 00:23:18 -0700700 char *from_name, *to_name;
701 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Jeff Dike84b3db02007-10-16 01:27:13 -0700703 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return -ENOMEM;
705 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700706 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700710 err = link_file(to_name, from_name);
711 kfree(from_name);
712 kfree(to_name);
713 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714}
715
716int hostfs_unlink(struct inode *ino, struct dentry *dentry)
717{
718 char *file;
719 int err;
720
Jeff Dike84b3db02007-10-16 01:27:13 -0700721 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700722 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700723 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 err = unlink_file(file);
727 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700728 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
731int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
732{
733 char *file;
734 int err;
735
Jeff Dike84b3db02007-10-16 01:27:13 -0700736 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700737 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 err = make_symlink(file, to);
739 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
744{
745 char *file;
746 int err;
747
Jeff Dike84b3db02007-10-16 01:27:13 -0700748 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700749 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 err = do_mkdir(file, mode);
751 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700752 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
755int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
756{
757 char *file;
758 int err;
759
Jeff Dike84b3db02007-10-16 01:27:13 -0700760 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700761 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 err = do_rmdir(file);
763 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700764 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765}
766
767int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
768{
769 struct inode *inode;
770 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800771 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
David Howells0a370e52008-02-07 00:15:50 -0800773 inode = hostfs_iget(dir->i_sb);
774 if (IS_ERR(inode)) {
775 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
779 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700780 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 goto out_put;
782
783 err = -ENOMEM;
784 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700785 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 goto out_put;
787
788 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800789 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700790 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 goto out_free;
792
793 err = read_name(inode, name);
794 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700795 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 goto out_put;
797
798 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700799 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 out_free:
802 kfree(name);
803 out_put:
804 iput(inode);
805 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700806 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807}
808
809int hostfs_rename(struct inode *from_ino, struct dentry *from,
810 struct inode *to_ino, struct dentry *to)
811{
812 char *from_name, *to_name;
813 int err;
814
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700816 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700819 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821 err = rename_file(from_name, to_name);
822 kfree(from_name);
823 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700824 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825}
826
Al Viroe6305c42008-07-15 21:03:57 -0400827int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
829 char *name;
830 int r = 0, w = 0, x = 0, err;
831
832 if (desired & MAY_READ) r = 1;
833 if (desired & MAY_WRITE) w = 1;
834 if (desired & MAY_EXEC) x = 1;
835 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700836 if (name == NULL)
837 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700840 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 err = 0;
842 else
843 err = access_file(name, r, w, x);
844 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 err = generic_permission(ino, desired, NULL);
847 return err;
848}
849
850int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
851{
852 struct hostfs_iattr attrs;
853 char *name;
854 int err;
855
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700856 int fd = HOSTFS_I(dentry->d_inode)->fd;
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 err = inode_change_ok(dentry->d_inode, attr);
859 if (err)
860 return err;
861
Jeff Dike84b3db02007-10-16 01:27:13 -0700862 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 attr->ia_valid &= ~ATTR_SIZE;
864
865 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700866 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 attrs.ia_valid |= HOSTFS_ATTR_MODE;
868 attrs.ia_mode = attr->ia_mode;
869 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700870 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 attrs.ia_valid |= HOSTFS_ATTR_UID;
872 attrs.ia_uid = attr->ia_uid;
873 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700874 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 attrs.ia_valid |= HOSTFS_ATTR_GID;
876 attrs.ia_gid = attr->ia_gid;
877 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700878 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
880 attrs.ia_size = attr->ia_size;
881 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700882 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
884 attrs.ia_atime = attr->ia_atime;
885 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700886 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
888 attrs.ia_mtime = attr->ia_mtime;
889 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700890 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
892 attrs.ia_ctime = attr->ia_ctime;
893 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700894 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
896 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700897 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
899 }
900 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700901 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700902 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700903 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700905 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700906 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Jeff Dikef1adc052007-05-08 00:23:18 -0700908 return inode_setattr(dentry->d_inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909}
910
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800911static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 .create = hostfs_create,
913 .link = hostfs_link,
914 .unlink = hostfs_unlink,
915 .symlink = hostfs_symlink,
916 .mkdir = hostfs_mkdir,
917 .rmdir = hostfs_rmdir,
918 .mknod = hostfs_mknod,
919 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 .permission = hostfs_permission,
921 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922};
923
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800924static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 .create = hostfs_create,
926 .lookup = hostfs_lookup,
927 .link = hostfs_link,
928 .unlink = hostfs_unlink,
929 .symlink = hostfs_symlink,
930 .mkdir = hostfs_mkdir,
931 .rmdir = hostfs_rmdir,
932 .mknod = hostfs_mknod,
933 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 .permission = hostfs_permission,
935 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936};
937
938int hostfs_link_readpage(struct file *file, struct page *page)
939{
940 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 int err;
942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 buffer = kmap(page);
944 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700945 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700946 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800947 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700949 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700951 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 flush_dcache_page(page);
953 SetPageUptodate(page);
954 if (PageError(page)) ClearPageError(page);
955 err = 0;
956 }
957 kunmap(page);
958 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700959 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960}
961
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700962static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 .readpage = hostfs_link_readpage,
964};
965
966static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
967{
968 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700969 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 int err;
971
972 sb->s_blocksize = 1024;
973 sb->s_blocksize_bits = 10;
974 sb->s_magic = HOSTFS_SUPER_MAGIC;
975 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700976 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800978 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700979 if (req_root == NULL)
980 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 err = -ENOMEM;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700983 host_root_path = kmalloc(strlen(root_ino) + 1
984 + strlen(req_root) + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700985 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 goto out;
987
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700988 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
David Howells0a370e52008-02-07 00:15:50 -0800990 root_inode = hostfs_iget(sb);
991 if (IS_ERR(root_inode)) {
992 err = PTR_ERR(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 goto out_free;
David Howells0a370e52008-02-07 00:15:50 -0800994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700997 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 goto out_put;
999
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001000 HOSTFS_I(root_inode)->host_filename = host_root_path;
Jeff Dike84b3db02007-10-16 01:27:13 -07001001 /*
1002 * Avoid that in the error path, iput(root_inode) frees again
1003 * host_root_path through hostfs_destroy_inode!
1004 */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001005 host_root_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007 err = -ENOMEM;
1008 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001009 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 goto out_put;
1011
David Howells0a370e52008-02-07 00:15:50 -08001012 err = hostfs_read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -07001013 if (err) {
Jeff Dikef1adc052007-05-08 00:23:18 -07001014 /* No iput in this case because the dput does that for us */
1015 dput(sb->s_root);
1016 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -08001017 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -07001018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Jeff Dikef1adc052007-05-08 00:23:18 -07001020 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Jeff Dikef1adc052007-05-08 00:23:18 -07001022out_put:
1023 iput(root_inode);
1024out_free:
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -07001025 kfree(host_root_path);
Jeff Dikef1adc052007-05-08 00:23:18 -07001026out:
1027 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028}
1029
David Howells454e2392006-06-23 02:02:57 -07001030static int hostfs_read_sb(struct file_system_type *type,
1031 int flags, const char *dev_name,
1032 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
David Howells454e2392006-06-23 02:02:57 -07001034 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035}
1036
1037static struct file_system_type hostfs_type = {
1038 .owner = THIS_MODULE,
1039 .name = "hostfs",
1040 .get_sb = hostfs_read_sb,
1041 .kill_sb = kill_anon_super,
1042 .fs_flags = 0,
1043};
1044
1045static int __init init_hostfs(void)
1046{
Jeff Dikef1adc052007-05-08 00:23:18 -07001047 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048}
1049
1050static void __exit exit_hostfs(void)
1051{
1052 unregister_filesystem(&hostfs_type);
1053}
1054
1055module_init(init_hostfs)
1056module_exit(exit_hostfs)
1057MODULE_LICENSE("GPL");