blob: 39dc505ed27310d651fdb924ef7e4b9d80609736 [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>
Al Virod0352d32010-06-06 21:51:16 -040017#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070020#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 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
Nick Pigginfe15ce42011-01-07 17:49:23 +110035static int hostfs_d_delete(const 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;
Al Virod0352d32010-06-06 21:51:16 -040052static const struct inode_operations hostfs_link_iops;
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
Al Viroe9193052010-06-06 23:16:34 -040093static char *__dentry_name(struct dentry *dentry, char *name)
94{
Nick Pigginec2447c2011-01-07 17:49:29 +110095 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040096 char *root;
97 size_t len;
98
Al Viroe9193052010-06-06 23:16:34 -040099 root = dentry->d_sb->s_fs_info;
100 len = strlen(root);
101 if (IS_ERR(p)) {
102 __putname(name);
103 return NULL;
104 }
Al Viro850a4962010-08-18 06:18:57 -0400105 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400106 if (len > p - name) {
107 __putname(name);
108 return NULL;
109 }
110 if (p > name + len) {
111 char *s = name + len;
112 while ((*s++ = *p++) != '\0')
113 ;
114 }
115 return name;
116}
117
Al Viroc5322222010-06-06 20:42:10 -0400118static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
Al Viroe9193052010-06-06 23:16:34 -0400120 char *name = __getname();
121 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700122 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Al Viroe9193052010-06-06 23:16:34 -0400124 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Al Viroc5322222010-06-06 20:42:10 -0400127static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
129 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100130 char *name;
131
132 dentry = d_find_alias(ino);
133 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400134 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Nick Pigginec2447c2011-01-07 17:49:29 +1100136 name = dentry_name(dentry);
137
138 dput(dentry);
139
140 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static char *follow_link(char *link)
144{
145 int len, n;
146 char *name, *resolved, *end;
147
148 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700149 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 n = -ENOMEM;
151 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700152 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto out;
154
WANG Congea7e7432008-11-19 15:36:46 -0800155 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700156 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 break;
158 len *= 2;
159 kfree(name);
160 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700161 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 goto out_free;
163
Jeff Dike84b3db02007-10-16 01:27:13 -0700164 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700165 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700169 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 *(end + 1) = '\0';
172 len = strlen(link) + strlen(name) + 1;
173
174 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700175 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 n = -ENOMEM;
177 goto out_free;
178 }
179
180 sprintf(resolved, "%s%s", link, name);
181 kfree(name);
182 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700183 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 out_free:
186 kfree(name);
187 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700188 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
David Howells0a370e52008-02-07 00:15:50 -0800191static struct inode *hostfs_iget(struct super_block *sb)
192{
Al Viro52b209f2010-06-06 18:43:19 -0400193 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800194 if (!inode)
195 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800196 return inode;
197}
198
David Howells726c3342006-06-23 02:02:58 -0700199int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
Jeff Dike84b3db02007-10-16 01:27:13 -0700201 /*
202 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 * struct statfs still has 32-bit versions for most of these fields,
204 * so we convert them here
205 */
206 int err;
207 long long f_blocks;
208 long long f_bfree;
209 long long f_bavail;
210 long long f_files;
211 long long f_ffree;
212
Al Viro601d2c32010-06-06 17:53:01 -0400213 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
215 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700216 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700217 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700218 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 sf->f_blocks = f_blocks;
220 sf->f_bfree = f_bfree;
221 sf->f_bavail = f_bavail;
222 sf->f_files = f_files;
223 sf->f_ffree = f_ffree;
224 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
228static struct inode *hostfs_alloc_inode(struct super_block *sb)
229{
230 struct hostfs_inode_info *hi;
231
Al Viro601d2c32010-06-06 17:53:01 -0400232 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700233 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700234 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400235 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700237 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
Al Viroe971a6d2010-06-06 15:16:17 -0400240static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
Mark Fashehfef26652005-09-09 13:01:31 -0700242 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400243 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700244 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 close_file(&HOSTFS_I(inode)->fd);
246 HOSTFS_I(inode)->fd = -1;
247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
250static void hostfs_destroy_inode(struct inode *inode)
251{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 kfree(HOSTFS_I(inode));
253}
254
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800255static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
256{
Al Viro601d2c32010-06-06 17:53:01 -0400257 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800258 size_t offset = strlen(root_ino) + 1;
259
260 if (strlen(root_path) > offset)
261 seq_printf(seq, ",%s", root_path + offset);
262
263 return 0;
264}
265
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800266static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400269 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800271 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272};
273
274int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
275{
276 void *dir;
277 char *name;
278 unsigned long long next, ino;
279 int error, len;
280
Al Viroc5322222010-06-06 20:42:10 -0400281 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700282 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700283 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400285 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700286 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700287 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 error = (*filldir)(ent, name, len, file->f_pos,
291 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700292 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 file->f_pos = next;
294 }
295 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700296 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
299int hostfs_file_open(struct inode *ino, struct file *file)
300{
Al Virof8ad8502010-06-06 23:49:18 -0400301 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400303 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400304 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400305 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700308 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700309 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Al Virof8ad8502010-06-06 23:49:18 -0400311 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Al Virof8ad8502010-06-06 23:49:18 -0400313retry:
314 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400316 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700318 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 r = 1;
320
Al Viroc5322222010-06-06 20:42:10 -0400321 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700322 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700323 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400326 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700327 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700328 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400329
330 mutex_lock(&open_mutex);
331 /* somebody else had handled it first? */
332 if ((mode & HOSTFS_I(ino)->mode) == mode) {
333 mutex_unlock(&open_mutex);
334 return 0;
335 }
336 if ((mode | HOSTFS_I(ino)->mode) != mode) {
337 mode |= HOSTFS_I(ino)->mode;
338 mutex_unlock(&open_mutex);
339 close_file(&fd);
340 goto retry;
341 }
342 if (HOSTFS_I(ino)->fd == -1) {
343 HOSTFS_I(ino)->fd = fd;
344 } else {
345 err = replace_file(fd, HOSTFS_I(ino)->fd);
346 close_file(&fd);
347 if (err < 0) {
348 mutex_unlock(&open_mutex);
349 return err;
350 }
351 }
352 HOSTFS_I(ino)->mode = mode;
353 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Jeff Dikef1adc052007-05-08 00:23:18 -0700355 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200358int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200360 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800363static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700365 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200366 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 .aio_read = generic_file_aio_read,
368 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700369 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 .mmap = generic_file_mmap,
371 .open = hostfs_file_open,
372 .release = NULL,
373 .fsync = hostfs_fsync,
374};
375
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800376static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 .llseek = generic_file_llseek,
378 .readdir = hostfs_readdir,
379 .read = generic_read_dir,
380};
381
382int hostfs_writepage(struct page *page, struct writeback_control *wbc)
383{
384 struct address_space *mapping = page->mapping;
385 struct inode *inode = mapping->host;
386 char *buffer;
387 unsigned long long base;
388 int count = PAGE_CACHE_SIZE;
389 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
390 int err;
391
392 if (page->index >= end_index)
393 count = inode->i_size & (PAGE_CACHE_SIZE-1);
394
395 buffer = kmap(page);
396 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
397
398 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700399 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 ClearPageUptodate(page);
401 goto out;
402 }
403
404 if (base > inode->i_size)
405 inode->i_size = base;
406
407 if (PageError(page))
408 ClearPageError(page);
409 err = 0;
410
411 out:
412 kunmap(page);
413
414 unlock_page(page);
415 return err;
416}
417
418int hostfs_readpage(struct file *file, struct page *page)
419{
420 char *buffer;
421 long long start;
422 int err = 0;
423
424 start = (long long) page->index << PAGE_CACHE_SHIFT;
425 buffer = kmap(page);
426 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
427 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700428 if (err < 0)
429 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
432
433 flush_dcache_page(page);
434 SetPageUptodate(page);
435 if (PageError(page)) ClearPageError(page);
436 err = 0;
437 out:
438 kunmap(page);
439 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700440 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441}
442
Nick Pigginae361ff2007-10-16 01:25:17 -0700443int hostfs_write_begin(struct file *file, struct address_space *mapping,
444 loff_t pos, unsigned len, unsigned flags,
445 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Nick Pigginae361ff2007-10-16 01:25:17 -0700447 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Nick Piggin54566b22009-01-04 12:00:53 -0800449 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700450 if (!*pagep)
451 return -ENOMEM;
452 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
Nick Pigginae361ff2007-10-16 01:25:17 -0700455int hostfs_write_end(struct file *file, struct address_space *mapping,
456 loff_t pos, unsigned len, unsigned copied,
457 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700460 void *buffer;
461 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
462 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700465 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700467
468 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
469 SetPageUptodate(page);
470
Jeff Dike84b3db02007-10-16 01:27:13 -0700471 /*
472 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700473 * i_size against the last byte written.
474 */
475 if (err > 0 && (pos > inode->i_size))
476 inode->i_size = pos;
477 unlock_page(page);
478 page_cache_release(page);
479
Jeff Dikef1adc052007-05-08 00:23:18 -0700480 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700483static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 .writepage = hostfs_writepage,
485 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700486 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700487 .write_begin = hostfs_write_begin,
488 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489};
490
Al Viro4754b822010-06-06 20:33:12 -0400491static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Al Viro4754b822010-06-06 20:33:12 -0400493 dev_t rdev;
494 struct hostfs_stat st;
495 int err = stat_file(name, &st, -1);
496 if (err)
497 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Al Viro5e2df282010-06-06 19:38:18 -0400499 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400500 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Al Viro4754b822010-06-06 20:33:12 -0400502 switch (st.mode & S_IFMT) {
503 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400504 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400505 break;
506 case S_IFDIR:
507 ino->i_op = &hostfs_dir_iops;
508 ino->i_fop = &hostfs_dir_fops;
509 break;
510 case S_IFCHR:
511 case S_IFBLK:
512 case S_IFIFO:
513 case S_IFSOCK:
514 init_special_inode(ino, st.mode & S_IFMT, rdev);
515 ino->i_op = &hostfs_iops;
516 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Al Viro4754b822010-06-06 20:33:12 -0400518 default:
519 ino->i_op = &hostfs_iops;
520 ino->i_fop = &hostfs_file_fops;
521 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 }
Al Viro4754b822010-06-06 20:33:12 -0400523
524 ino->i_ino = st.ino;
525 ino->i_mode = st.mode;
526 ino->i_nlink = st.nlink;
527 ino->i_uid = st.uid;
528 ino->i_gid = st.gid;
529 ino->i_atime = st.atime;
530 ino->i_mtime = st.mtime;
531 ino->i_ctime = st.ctime;
532 ino->i_size = st.size;
533 ino->i_blocks = st.blocks;
534 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535}
536
537int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700538 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
540 struct inode *inode;
541 char *name;
542 int error, fd;
543
David Howells0a370e52008-02-07 00:15:50 -0800544 inode = hostfs_iget(dir->i_sb);
545 if (IS_ERR(inode)) {
546 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700547 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400551 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700552 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 goto out_put;
554
555 fd = file_create(name,
556 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
557 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
558 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400559 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400561 else
Al Viro5e2df282010-06-06 19:38:18 -0400562 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Al Viroe9193052010-06-06 23:16:34 -0400564 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 goto out_put;
567
568 HOSTFS_I(inode)->fd = fd;
569 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
570 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700571 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573 out_put:
574 iput(inode);
575 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700576 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578
579struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700580 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 struct inode *inode;
583 char *name;
584 int err;
585
David Howells0a370e52008-02-07 00:15:50 -0800586 inode = hostfs_iget(ino->i_sb);
587 if (IS_ERR(inode)) {
588 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400593 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700594 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 goto out_put;
596
597 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400598
Al Viroe9193052010-06-06 23:16:34 -0400599 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700600 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 iput(inode);
602 inode = NULL;
603 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700604 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 goto out_put;
606
607 d_add(dentry, inode);
608 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700609 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 out_put:
612 iput(inode);
613 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700614 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
618{
Jeff Dikef1adc052007-05-08 00:23:18 -0700619 char *from_name, *to_name;
620 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Al Viroc5322222010-06-06 20:42:10 -0400622 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700623 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400624 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700625 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400626 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700629 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400630 __putname(from_name);
631 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700632 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633}
634
635int hostfs_unlink(struct inode *ino, struct dentry *dentry)
636{
637 char *file;
638 int err;
639
Jeff Dike84b3db02007-10-16 01:27:13 -0700640 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Al Virof8d7e182010-06-06 23:19:04 -0400643 if ((file = dentry_name(dentry)) == NULL)
644 return -ENOMEM;
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400647 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700648 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650
651int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
652{
653 char *file;
654 int err;
655
Al Viroc5322222010-06-06 20:42:10 -0400656 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700657 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400659 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700660 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
663int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
664{
665 char *file;
666 int err;
667
Al Viroc5322222010-06-06 20:42:10 -0400668 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700669 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400671 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700672 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673}
674
675int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
676{
677 char *file;
678 int err;
679
Al Viroc5322222010-06-06 20:42:10 -0400680 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700681 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400683 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700684 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685}
686
687int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
688{
689 struct inode *inode;
690 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800691 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
David Howells0a370e52008-02-07 00:15:50 -0800693 inode = hostfs_iget(dir->i_sb);
694 if (IS_ERR(inode)) {
695 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400700 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700701 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 goto out_put;
703
704 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800705 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400706 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 goto out_free;
708
709 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400710 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400711 if (err)
712 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700713 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 goto out_put;
715
716 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700717 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400720 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 out_put:
722 iput(inode);
723 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
727int hostfs_rename(struct inode *from_ino, struct dentry *from,
728 struct inode *to_ino, struct dentry *to)
729{
730 char *from_name, *to_name;
731 int err;
732
Al Viroc5322222010-06-06 20:42:10 -0400733 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700734 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400735 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400736 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700737 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
739 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400740 __putname(from_name);
741 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700742 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}
744
Al Viroe6305c42008-07-15 21:03:57 -0400745int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 char *name;
748 int r = 0, w = 0, x = 0, err;
749
750 if (desired & MAY_READ) r = 1;
751 if (desired & MAY_WRITE) w = 1;
752 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400753 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700754 if (name == NULL)
755 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700758 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 err = 0;
760 else
761 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400762 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700763 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 err = generic_permission(ino, desired, NULL);
765 return err;
766}
767
768int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
769{
Christoph Hellwig10257742010-06-04 11:30:02 +0200770 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 struct hostfs_iattr attrs;
772 char *name;
773 int err;
774
Christoph Hellwig10257742010-06-04 11:30:02 +0200775 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700776
Christoph Hellwig10257742010-06-04 11:30:02 +0200777 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (err)
779 return err;
780
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 attr->ia_valid &= ~ATTR_SIZE;
783
784 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700785 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 attrs.ia_valid |= HOSTFS_ATTR_MODE;
787 attrs.ia_mode = attr->ia_mode;
788 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 attrs.ia_valid |= HOSTFS_ATTR_UID;
791 attrs.ia_uid = attr->ia_uid;
792 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700793 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 attrs.ia_valid |= HOSTFS_ATTR_GID;
795 attrs.ia_gid = attr->ia_gid;
796 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700797 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
799 attrs.ia_size = attr->ia_size;
800 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
803 attrs.ia_atime = attr->ia_atime;
804 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
807 attrs.ia_mtime = attr->ia_mtime;
808 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
811 attrs.ia_ctime = attr->ia_ctime;
812 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
815 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
818 }
Al Viroc5322222010-06-06 20:42:10 -0400819 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700821 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700822 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400823 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700825 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Christoph Hellwig10257742010-06-04 11:30:02 +0200827 if ((attr->ia_valid & ATTR_SIZE) &&
828 attr->ia_size != i_size_read(inode)) {
829 int error;
830
831 error = vmtruncate(inode, attr->ia_size);
832 if (err)
833 return err;
834 }
835
836 setattr_copy(inode, attr);
837 mark_inode_dirty(inode);
838 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839}
840
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800841static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 .create = hostfs_create,
843 .link = hostfs_link,
844 .unlink = hostfs_unlink,
845 .symlink = hostfs_symlink,
846 .mkdir = hostfs_mkdir,
847 .rmdir = hostfs_rmdir,
848 .mknod = hostfs_mknod,
849 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 .permission = hostfs_permission,
851 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852};
853
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800854static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 .create = hostfs_create,
856 .lookup = hostfs_lookup,
857 .link = hostfs_link,
858 .unlink = hostfs_unlink,
859 .symlink = hostfs_symlink,
860 .mkdir = hostfs_mkdir,
861 .rmdir = hostfs_rmdir,
862 .mknod = hostfs_mknod,
863 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 .permission = hostfs_permission,
865 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866};
867
Al Virod0352d32010-06-06 21:51:16 -0400868static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869{
Al Virod0352d32010-06-06 21:51:16 -0400870 char *link = __getname();
871 if (link) {
872 char *path = dentry_name(dentry);
873 int err = -ENOMEM;
874 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400875 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400876 if (err == PATH_MAX)
877 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400878 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400879 }
880 if (err < 0) {
881 __putname(link);
882 link = ERR_PTR(err);
883 }
884 } else {
885 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 }
Al Virod0352d32010-06-06 21:51:16 -0400887
888 nd_set_link(nd, link);
889 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890}
891
Al Virod0352d32010-06-06 21:51:16 -0400892static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
893{
894 char *s = nd_get_link(nd);
895 if (!IS_ERR(s))
896 __putname(s);
897}
898
899static const struct inode_operations hostfs_link_iops = {
900 .readlink = generic_readlink,
901 .follow_link = hostfs_follow_link,
902 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903};
904
905static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
906{
907 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700908 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 int err;
910
911 sb->s_blocksize = 1024;
912 sb->s_blocksize_bits = 10;
913 sb->s_magic = HOSTFS_SUPER_MAGIC;
914 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700915 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800917 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700918 if (req_root == NULL)
919 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400922 sb->s_fs_info = host_root_path =
923 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700924 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 goto out;
926
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700927 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Al Viro52b209f2010-06-06 18:43:19 -0400929 root_inode = new_inode(sb);
930 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400931 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Al Viro4754b822010-06-06 20:33:12 -0400933 err = read_name(root_inode, host_root_path);
934 if (err)
935 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400936
Al Viro4754b822010-06-06 20:33:12 -0400937 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400938 char *name = follow_link(host_root_path);
939 if (IS_ERR(name))
940 err = PTR_ERR(name);
941 else
942 err = read_name(root_inode, name);
943 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400944 if (err)
945 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 err = -ENOMEM;
949 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700950 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 goto out_put;
952
Jeff Dikef1adc052007-05-08 00:23:18 -0700953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Jeff Dikef1adc052007-05-08 00:23:18 -0700955out_put:
956 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700957out:
958 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
Al Viro3c26ff62010-07-25 11:46:36 +0400961static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700962 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400963 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
Al Viro3c26ff62010-07-25 11:46:36 +0400965 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Al Viro601d2c32010-06-06 17:53:01 -0400968static void hostfs_kill_sb(struct super_block *s)
969{
970 kill_anon_super(s);
971 kfree(s->s_fs_info);
972}
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974static struct file_system_type hostfs_type = {
975 .owner = THIS_MODULE,
976 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400977 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400978 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 .fs_flags = 0,
980};
981
982static int __init init_hostfs(void)
983{
Jeff Dikef1adc052007-05-08 00:23:18 -0700984 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
987static void __exit exit_hostfs(void)
988{
989 unregister_filesystem(&hostfs_type);
990}
991
992module_init(init_hostfs)
993module_exit(exit_hostfs)
994MODULE_LICENSE("GPL");