blob: fab5f5a1e6f039591e3b80848c37ee53c4253df2 [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
Al Viroe971a6d2010-06-06 15:16:17 -0400244 inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800245 if (!inode)
246 return ERR_PTR(-ENOMEM);
Al Viroe971a6d2010-06-06 15:16:17 -0400247 ret = hostfs_read_inode(inode);
248 if (ret < 0) {
249 iput(inode);
250 return ERR_PTR(ret);
David Howells0a370e52008-02-07 00:15:50 -0800251 }
252 return inode;
253}
254
David Howells726c3342006-06-23 02:02:58 -0700255int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
Jeff Dike84b3db02007-10-16 01:27:13 -0700257 /*
258 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 * struct statfs still has 32-bit versions for most of these fields,
260 * so we convert them here
261 */
262 int err;
263 long long f_blocks;
264 long long f_bfree;
265 long long f_bavail;
266 long long f_files;
267 long long f_ffree;
268
David Howells726c3342006-06-23 02:02:58 -0700269 err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
271 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
272 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700273 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700274 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 sf->f_blocks = f_blocks;
276 sf->f_bfree = f_bfree;
277 sf->f_bavail = f_bavail;
278 sf->f_files = f_files;
279 sf->f_ffree = f_ffree;
280 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700281 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282}
283
284static struct inode *hostfs_alloc_inode(struct super_block *sb)
285{
286 struct hostfs_inode_info *hi;
287
288 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
293 .fd = -1,
294 .mode = 0 });
295 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700296 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Al Viroe971a6d2010-06-06 15:16:17 -0400299static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Mark Fashehfef26652005-09-09 13:01:31 -0700301 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400302 end_writeback(inode);
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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
309static void hostfs_destroy_inode(struct inode *inode)
310{
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800311 kfree(HOSTFS_I(inode)->host_filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 kfree(HOSTFS_I(inode));
313}
314
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800315static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
316{
317 struct inode *root = vfs->mnt_sb->s_root->d_inode;
318 const char *root_path = HOSTFS_I(root)->host_filename;
319 size_t offset = strlen(root_ino) + 1;
320
321 if (strlen(root_path) > offset)
322 seq_printf(seq, ",%s", root_path + offset);
323
324 return 0;
325}
326
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800327static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400330 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800332 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333};
334
335int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
336{
337 void *dir;
338 char *name;
339 unsigned long long next, ino;
340 int error, len;
341
Josef Sipek680b0da2006-12-08 02:37:05 -0800342 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700343 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700344 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 dir = open_dir(name, &error);
346 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700347 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700348 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700350 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 error = (*filldir)(ent, name, len, file->f_pos,
352 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700353 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 file->f_pos = next;
355 }
356 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700357 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358}
359
360int hostfs_file_open(struct inode *ino, struct file *file)
361{
362 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400363 fmode_t mode = 0;
364 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700367 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700368 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Jeff Dike84b3db02007-10-16 01:27:13 -0700370 /*
371 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 * so this resets things and reopens the file with the new access.
373 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700374 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 close_file(&HOSTFS_I(ino)->fd);
376 HOSTFS_I(ino)->fd = -1;
377 }
378
379 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700380 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700382 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700384 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 r = 1;
386
Josef Sipek680b0da2006-12-08 02:37:05 -0800387 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700388 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700389 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
391 fd = open_file(name, r, w, append);
392 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700393 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700394 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 FILE_HOSTFS_I(file)->fd = fd;
396
Jeff Dikef1adc052007-05-08 00:23:18 -0700397 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200400int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200402 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800405static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700407 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200408 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 .aio_read = generic_file_aio_read,
410 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700411 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 .mmap = generic_file_mmap,
413 .open = hostfs_file_open,
414 .release = NULL,
415 .fsync = hostfs_fsync,
416};
417
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800418static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 .llseek = generic_file_llseek,
420 .readdir = hostfs_readdir,
421 .read = generic_read_dir,
422};
423
424int hostfs_writepage(struct page *page, struct writeback_control *wbc)
425{
426 struct address_space *mapping = page->mapping;
427 struct inode *inode = mapping->host;
428 char *buffer;
429 unsigned long long base;
430 int count = PAGE_CACHE_SIZE;
431 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
432 int err;
433
434 if (page->index >= end_index)
435 count = inode->i_size & (PAGE_CACHE_SIZE-1);
436
437 buffer = kmap(page);
438 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
439
440 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700441 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 ClearPageUptodate(page);
443 goto out;
444 }
445
446 if (base > inode->i_size)
447 inode->i_size = base;
448
449 if (PageError(page))
450 ClearPageError(page);
451 err = 0;
452
453 out:
454 kunmap(page);
455
456 unlock_page(page);
457 return err;
458}
459
460int hostfs_readpage(struct file *file, struct page *page)
461{
462 char *buffer;
463 long long start;
464 int err = 0;
465
466 start = (long long) page->index << PAGE_CACHE_SHIFT;
467 buffer = kmap(page);
468 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
469 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700470 if (err < 0)
471 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
473 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
474
475 flush_dcache_page(page);
476 SetPageUptodate(page);
477 if (PageError(page)) ClearPageError(page);
478 err = 0;
479 out:
480 kunmap(page);
481 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700482 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Nick Pigginae361ff2007-10-16 01:25:17 -0700485int hostfs_write_begin(struct file *file, struct address_space *mapping,
486 loff_t pos, unsigned len, unsigned flags,
487 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Nick Piggin54566b22009-01-04 12:00:53 -0800491 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700492 if (!*pagep)
493 return -ENOMEM;
494 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Nick Pigginae361ff2007-10-16 01:25:17 -0700497int hostfs_write_end(struct file *file, struct address_space *mapping,
498 loff_t pos, unsigned len, unsigned copied,
499 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700502 void *buffer;
503 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
504 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700507 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700509
510 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
511 SetPageUptodate(page);
512
Jeff Dike84b3db02007-10-16 01:27:13 -0700513 /*
514 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700515 * i_size against the last byte written.
516 */
517 if (err > 0 && (pos > inode->i_size))
518 inode->i_size = pos;
519 unlock_page(page);
520 page_cache_release(page);
521
Jeff Dikef1adc052007-05-08 00:23:18 -0700522 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700525static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 .writepage = hostfs_writepage,
527 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700528 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700529 .write_begin = hostfs_write_begin,
530 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531};
532
533static int init_inode(struct inode *inode, struct dentry *dentry)
534{
535 char *name;
536 int type, err = -ENOMEM;
537 int maj, min;
538 dev_t rdev = 0;
539
Jeff Dike84b3db02007-10-16 01:27:13 -0700540 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700542 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 goto out;
544 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700545 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 rdev = MKDEV(maj, min);
547 kfree(name);
548 }
549 else type = OS_TYPE_DIR;
550
551 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700552 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700554 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 inode->i_op = &hostfs_dir_iops;
556 else inode->i_op = &hostfs_iops;
557
Jeff Dike84b3db02007-10-16 01:27:13 -0700558 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 else inode->i_fop = &hostfs_file_fops;
560
Jeff Dike84b3db02007-10-16 01:27:13 -0700561 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 inode->i_mapping->a_ops = &hostfs_link_aops;
563 else inode->i_mapping->a_ops = &hostfs_aops;
564
565 switch (type) {
566 case OS_TYPE_CHARDEV:
567 init_special_inode(inode, S_IFCHR, rdev);
568 break;
569 case OS_TYPE_BLOCKDEV:
570 init_special_inode(inode, S_IFBLK, rdev);
571 break;
572 case OS_TYPE_FIFO:
573 init_special_inode(inode, S_IFIFO, 0);
574 break;
575 case OS_TYPE_SOCK:
576 init_special_inode(inode, S_IFSOCK, 0);
577 break;
578 }
579 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700580 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581}
582
583int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700584 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 struct inode *inode;
587 char *name;
588 int error, fd;
589
David Howells0a370e52008-02-07 00:15:50 -0800590 inode = hostfs_iget(dir->i_sb);
591 if (IS_ERR(inode)) {
592 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700593 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700597 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 goto out_put;
599
600 error = -ENOMEM;
601 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700602 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 goto out_put;
604
605 fd = file_create(name,
606 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
607 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
608 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700609 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 error = fd;
611 else error = read_name(inode, name);
612
613 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700614 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 goto out_put;
616
617 HOSTFS_I(inode)->fd = fd;
618 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
619 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700620 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 out_put:
623 iput(inode);
624 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700625 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626}
627
628struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700629 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
631 struct inode *inode;
632 char *name;
633 int err;
634
David Howells0a370e52008-02-07 00:15:50 -0800635 inode = hostfs_iget(ino->i_sb);
636 if (IS_ERR(inode)) {
637 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700642 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 goto out_put;
644
645 err = -ENOMEM;
646 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700647 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 goto out_put;
649
650 err = read_name(inode, name);
651 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700652 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 iput(inode);
654 inode = NULL;
655 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700656 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 goto out_put;
658
659 d_add(dentry, inode);
660 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700661 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
663 out_put:
664 iput(inode);
665 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
669static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
670{
Jeff Dikef1adc052007-05-08 00:23:18 -0700671 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 int len;
673
674 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700675 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return NULL;
677 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700679 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700681 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
684int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
685{
Jeff Dikef1adc052007-05-08 00:23:18 -0700686 char *from_name, *to_name;
687 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Jeff Dike84b3db02007-10-16 01:27:13 -0700689 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -ENOMEM;
691 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700692 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700694 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700696 err = link_file(to_name, from_name);
697 kfree(from_name);
698 kfree(to_name);
699 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
702int hostfs_unlink(struct inode *ino, struct dentry *dentry)
703{
704 char *file;
705 int err;
706
Jeff Dike84b3db02007-10-16 01:27:13 -0700707 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700709 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700710 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 err = unlink_file(file);
713 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700714 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715}
716
717int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
718{
719 char *file;
720 int err;
721
Jeff Dike84b3db02007-10-16 01:27:13 -0700722 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700723 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 err = make_symlink(file, to);
725 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700726 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
729int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
730{
731 char *file;
732 int err;
733
Jeff Dike84b3db02007-10-16 01:27:13 -0700734 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700735 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 err = do_mkdir(file, mode);
737 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700738 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
742{
743 char *file;
744 int err;
745
Jeff Dike84b3db02007-10-16 01:27:13 -0700746 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700747 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 err = do_rmdir(file);
749 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700750 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751}
752
753int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
754{
755 struct inode *inode;
756 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800757 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
David Howells0a370e52008-02-07 00:15:50 -0800759 inode = hostfs_iget(dir->i_sb);
760 if (IS_ERR(inode)) {
761 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700766 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 goto out_put;
768
769 err = -ENOMEM;
770 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700771 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 goto out_put;
773
774 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800775 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700776 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 goto out_free;
778
779 err = read_name(inode, name);
780 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 goto out_put;
783
784 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700785 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 out_free:
788 kfree(name);
789 out_put:
790 iput(inode);
791 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700792 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795int hostfs_rename(struct inode *from_ino, struct dentry *from,
796 struct inode *to_ino, struct dentry *to)
797{
798 char *from_name, *to_name;
799 int err;
800
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700802 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700803 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700805 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807 err = rename_file(from_name, to_name);
808 kfree(from_name);
809 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700810 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811}
812
Al Viroe6305c42008-07-15 21:03:57 -0400813int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 char *name;
816 int r = 0, w = 0, x = 0, err;
817
818 if (desired & MAY_READ) r = 1;
819 if (desired & MAY_WRITE) w = 1;
820 if (desired & MAY_EXEC) x = 1;
821 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700822 if (name == NULL)
823 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700826 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 err = 0;
828 else
829 err = access_file(name, r, w, x);
830 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 err = generic_permission(ino, desired, NULL);
833 return err;
834}
835
836int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
837{
Christoph Hellwig10257742010-06-04 11:30:02 +0200838 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 struct hostfs_iattr attrs;
840 char *name;
841 int err;
842
Christoph Hellwig10257742010-06-04 11:30:02 +0200843 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700844
Christoph Hellwig10257742010-06-04 11:30:02 +0200845 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (err)
847 return err;
848
Jeff Dike84b3db02007-10-16 01:27:13 -0700849 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 attr->ia_valid &= ~ATTR_SIZE;
851
852 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700853 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 attrs.ia_valid |= HOSTFS_ATTR_MODE;
855 attrs.ia_mode = attr->ia_mode;
856 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700857 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 attrs.ia_valid |= HOSTFS_ATTR_UID;
859 attrs.ia_uid = attr->ia_uid;
860 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700861 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 attrs.ia_valid |= HOSTFS_ATTR_GID;
863 attrs.ia_gid = attr->ia_gid;
864 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700865 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
867 attrs.ia_size = attr->ia_size;
868 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700869 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
871 attrs.ia_atime = attr->ia_atime;
872 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700873 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
875 attrs.ia_mtime = attr->ia_mtime;
876 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700877 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
879 attrs.ia_ctime = attr->ia_ctime;
880 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700881 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
883 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700884 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
886 }
887 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700888 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700889 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700890 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700892 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700893 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Christoph Hellwig10257742010-06-04 11:30:02 +0200895 if ((attr->ia_valid & ATTR_SIZE) &&
896 attr->ia_size != i_size_read(inode)) {
897 int error;
898
899 error = vmtruncate(inode, attr->ia_size);
900 if (err)
901 return err;
902 }
903
904 setattr_copy(inode, attr);
905 mark_inode_dirty(inode);
906 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800909static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 .create = hostfs_create,
911 .link = hostfs_link,
912 .unlink = hostfs_unlink,
913 .symlink = hostfs_symlink,
914 .mkdir = hostfs_mkdir,
915 .rmdir = hostfs_rmdir,
916 .mknod = hostfs_mknod,
917 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 .permission = hostfs_permission,
919 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920};
921
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800922static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 .create = hostfs_create,
924 .lookup = hostfs_lookup,
925 .link = hostfs_link,
926 .unlink = hostfs_unlink,
927 .symlink = hostfs_symlink,
928 .mkdir = hostfs_mkdir,
929 .rmdir = hostfs_rmdir,
930 .mknod = hostfs_mknod,
931 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 .permission = hostfs_permission,
933 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934};
935
936int hostfs_link_readpage(struct file *file, struct page *page)
937{
938 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 int err;
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 buffer = kmap(page);
942 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700943 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700944 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800945 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700947 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700949 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 flush_dcache_page(page);
951 SetPageUptodate(page);
952 if (PageError(page)) ClearPageError(page);
953 err = 0;
954 }
955 kunmap(page);
956 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700957 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958}
959
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700960static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 .readpage = hostfs_link_readpage,
962};
963
964static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
965{
966 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700967 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 int err;
969
970 sb->s_blocksize = 1024;
971 sb->s_blocksize_bits = 10;
972 sb->s_magic = HOSTFS_SUPER_MAGIC;
973 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700974 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
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");