blob: e130bd46d671515762152d071194ce9e9a3bb4a6 [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
Nick Pigginfa0d7e32011-01-07 17:49:49 +1100250static void hostfs_i_callback(struct rcu_head *head)
251{
252 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e32011-01-07 17:49:49 +1100253 kfree(HOSTFS_I(inode));
254}
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256static void hostfs_destroy_inode(struct inode *inode)
257{
Nick Pigginfa0d7e32011-01-07 17:49:49 +1100258 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
Al Viro34c80b12011-12-08 21:32:45 -0500261static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262{
Al Viro34c80b12011-12-08 21:32:45 -0500263 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800264 size_t offset = strlen(root_ino) + 1;
265
266 if (strlen(root_path) > offset)
267 seq_printf(seq, ",%s", root_path + offset);
268
269 return 0;
270}
271
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800272static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400275 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800277 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278};
279
280int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
281{
282 void *dir;
283 char *name;
284 unsigned long long next, ino;
285 int error, len;
286
Al Viroc5322222010-06-06 20:42:10 -0400287 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700288 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700289 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400291 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700292 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700293 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700295 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 error = (*filldir)(ent, name, len, file->f_pos,
297 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700298 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 file->f_pos = next;
300 }
301 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700302 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
305int hostfs_file_open(struct inode *ino, struct file *file)
306{
Al Virof8ad8502010-06-06 23:49:18 -0400307 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400309 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400310 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400311 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700314 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700315 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Al Virof8ad8502010-06-06 23:49:18 -0400317 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Al Virof8ad8502010-06-06 23:49:18 -0400319retry:
320 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400322 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700324 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 r = 1;
326
Al Viroc5322222010-06-06 20:42:10 -0400327 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700328 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700329 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400332 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700333 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700334 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400335
336 mutex_lock(&open_mutex);
337 /* somebody else had handled it first? */
338 if ((mode & HOSTFS_I(ino)->mode) == mode) {
339 mutex_unlock(&open_mutex);
340 return 0;
341 }
342 if ((mode | HOSTFS_I(ino)->mode) != mode) {
343 mode |= HOSTFS_I(ino)->mode;
344 mutex_unlock(&open_mutex);
345 close_file(&fd);
346 goto retry;
347 }
348 if (HOSTFS_I(ino)->fd == -1) {
349 HOSTFS_I(ino)->fd = fd;
350 } else {
351 err = replace_file(fd, HOSTFS_I(ino)->fd);
352 close_file(&fd);
353 if (err < 0) {
354 mutex_unlock(&open_mutex);
355 return err;
356 }
357 }
358 HOSTFS_I(ino)->mode = mode;
359 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Jeff Dikef1adc052007-05-08 00:23:18 -0700361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Josef Bacik02c24a82011-07-16 20:44:56 -0400364int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Josef Bacik02c24a82011-07-16 20:44:56 -0400366 struct inode *inode = file->f_mapping->host;
367 int ret;
368
369 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
370 if (ret)
371 return ret;
372
373 mutex_lock(&inode->i_mutex);
374 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
375 mutex_unlock(&inode->i_mutex);
376
377 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800380static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700382 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200383 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 .aio_read = generic_file_aio_read,
385 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700386 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 .mmap = generic_file_mmap,
388 .open = hostfs_file_open,
389 .release = NULL,
390 .fsync = hostfs_fsync,
391};
392
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800393static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .llseek = generic_file_llseek,
395 .readdir = hostfs_readdir,
396 .read = generic_read_dir,
397};
398
399int hostfs_writepage(struct page *page, struct writeback_control *wbc)
400{
401 struct address_space *mapping = page->mapping;
402 struct inode *inode = mapping->host;
403 char *buffer;
404 unsigned long long base;
405 int count = PAGE_CACHE_SIZE;
406 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
407 int err;
408
409 if (page->index >= end_index)
410 count = inode->i_size & (PAGE_CACHE_SIZE-1);
411
412 buffer = kmap(page);
413 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
414
415 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700416 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 ClearPageUptodate(page);
418 goto out;
419 }
420
421 if (base > inode->i_size)
422 inode->i_size = base;
423
424 if (PageError(page))
425 ClearPageError(page);
426 err = 0;
427
428 out:
429 kunmap(page);
430
431 unlock_page(page);
432 return err;
433}
434
435int hostfs_readpage(struct file *file, struct page *page)
436{
437 char *buffer;
438 long long start;
439 int err = 0;
440
441 start = (long long) page->index << PAGE_CACHE_SHIFT;
442 buffer = kmap(page);
443 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
444 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700445 if (err < 0)
446 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
449
450 flush_dcache_page(page);
451 SetPageUptodate(page);
452 if (PageError(page)) ClearPageError(page);
453 err = 0;
454 out:
455 kunmap(page);
456 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700457 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Nick Pigginae361ff2007-10-16 01:25:17 -0700460int hostfs_write_begin(struct file *file, struct address_space *mapping,
461 loff_t pos, unsigned len, unsigned flags,
462 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Nick Pigginae361ff2007-10-16 01:25:17 -0700464 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Nick Piggin54566b22009-01-04 12:00:53 -0800466 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700467 if (!*pagep)
468 return -ENOMEM;
469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
Nick Pigginae361ff2007-10-16 01:25:17 -0700472int hostfs_write_end(struct file *file, struct address_space *mapping,
473 loff_t pos, unsigned len, unsigned copied,
474 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700477 void *buffer;
478 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
479 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700482 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700484
485 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
486 SetPageUptodate(page);
487
Jeff Dike84b3db02007-10-16 01:27:13 -0700488 /*
489 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700490 * i_size against the last byte written.
491 */
492 if (err > 0 && (pos > inode->i_size))
493 inode->i_size = pos;
494 unlock_page(page);
495 page_cache_release(page);
496
Jeff Dikef1adc052007-05-08 00:23:18 -0700497 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700500static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 .writepage = hostfs_writepage,
502 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700503 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700504 .write_begin = hostfs_write_begin,
505 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506};
507
Al Viro4754b822010-06-06 20:33:12 -0400508static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
Al Viro4754b822010-06-06 20:33:12 -0400510 dev_t rdev;
511 struct hostfs_stat st;
512 int err = stat_file(name, &st, -1);
513 if (err)
514 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Al Viro5e2df282010-06-06 19:38:18 -0400516 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400517 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Al Viro4754b822010-06-06 20:33:12 -0400519 switch (st.mode & S_IFMT) {
520 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400521 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400522 break;
523 case S_IFDIR:
524 ino->i_op = &hostfs_dir_iops;
525 ino->i_fop = &hostfs_dir_fops;
526 break;
527 case S_IFCHR:
528 case S_IFBLK:
529 case S_IFIFO:
530 case S_IFSOCK:
531 init_special_inode(ino, st.mode & S_IFMT, rdev);
532 ino->i_op = &hostfs_iops;
533 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Al Viro4754b822010-06-06 20:33:12 -0400535 default:
536 ino->i_op = &hostfs_iops;
537 ino->i_fop = &hostfs_file_fops;
538 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Al Viro4754b822010-06-06 20:33:12 -0400540
541 ino->i_ino = st.ino;
542 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200543 set_nlink(ino, st.nlink);
Al Viro4754b822010-06-06 20:33:12 -0400544 ino->i_uid = st.uid;
545 ino->i_gid = st.gid;
546 ino->i_atime = st.atime;
547 ino->i_mtime = st.mtime;
548 ino->i_ctime = st.ctime;
549 ino->i_size = st.size;
550 ino->i_blocks = st.blocks;
551 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
Al Viro4acdaf22011-07-26 01:42:34 -0400554int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700555 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 struct inode *inode;
558 char *name;
559 int error, fd;
560
David Howells0a370e52008-02-07 00:15:50 -0800561 inode = hostfs_iget(dir->i_sb);
562 if (IS_ERR(inode)) {
563 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700564 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400568 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 goto out_put;
571
572 fd = file_create(name,
573 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
574 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
575 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400576 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400578 else
Al Viro5e2df282010-06-06 19:38:18 -0400579 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Al Viroe9193052010-06-06 23:16:34 -0400581 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700582 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 goto out_put;
584
585 HOSTFS_I(inode)->fd = fd;
586 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
587 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700588 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590 out_put:
591 iput(inode);
592 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700593 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
596struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700597 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 struct inode *inode;
600 char *name;
601 int err;
602
David Howells0a370e52008-02-07 00:15:50 -0800603 inode = hostfs_iget(ino->i_sb);
604 if (IS_ERR(inode)) {
605 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400610 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400615
Al Viroe9193052010-06-06 23:16:34 -0400616 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700617 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 iput(inode);
619 inode = NULL;
620 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700621 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 goto out_put;
623
624 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700625 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627 out_put:
628 iput(inode);
629 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
634{
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 char *from_name, *to_name;
636 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Al Viroc5322222010-06-06 20:42:10 -0400638 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400640 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700641 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400642 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400646 __putname(from_name);
647 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700648 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650
651int hostfs_unlink(struct inode *ino, struct dentry *dentry)
652{
653 char *file;
654 int err;
655
Jeff Dike84b3db02007-10-16 01:27:13 -0700656 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700657 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Al Virof8d7e182010-06-06 23:19:04 -0400659 if ((file = dentry_name(dentry)) == NULL)
660 return -ENOMEM;
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400663 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700664 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
667int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
668{
669 char *file;
670 int err;
671
Al Viroc5322222010-06-06 20:42:10 -0400672 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400675 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
Al Viro18bb1db2011-07-26 01:41:39 -0400679int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 char *file;
682 int err;
683
Al Viroc5322222010-06-06 20:42:10 -0400684 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700685 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400687 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
691int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
692{
693 char *file;
694 int err;
695
Al Viroc5322222010-06-06 20:42:10 -0400696 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700697 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400699 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700700 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
Al Viro1a67aaf2011-07-26 01:52:52 -0400703static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
705 struct inode *inode;
706 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800707 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
David Howells0a370e52008-02-07 00:15:50 -0800709 inode = hostfs_iget(dir->i_sb);
710 if (IS_ERR(inode)) {
711 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400716 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700717 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 goto out_put;
719
720 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800721 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400722 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 goto out_free;
724
725 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400726 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400727 if (err)
728 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700729 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 goto out_put;
731
732 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700733 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400736 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 out_put:
738 iput(inode);
739 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743int hostfs_rename(struct inode *from_ino, struct dentry *from,
744 struct inode *to_ino, struct dentry *to)
745{
746 char *from_name, *to_name;
747 int err;
748
Al Viroc5322222010-06-06 20:42:10 -0400749 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700750 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400751 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400752 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700753 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 }
755 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400756 __putname(from_name);
757 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700758 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
Al Viro10556cb2011-06-20 19:28:19 -0400761int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 char *name;
764 int r = 0, w = 0, x = 0, err;
765
Al Viro10556cb2011-06-20 19:28:19 -0400766 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100767 return -ECHILD;
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (desired & MAY_READ) r = 1;
770 if (desired & MAY_WRITE) w = 1;
771 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400772 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700773 if (name == NULL)
774 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700777 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 err = 0;
779 else
780 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400781 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700782 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400783 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return err;
785}
786
787int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
788{
Christoph Hellwig10257742010-06-04 11:30:02 +0200789 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 struct hostfs_iattr attrs;
791 char *name;
792 int err;
793
Christoph Hellwig10257742010-06-04 11:30:02 +0200794 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700795
Christoph Hellwig10257742010-06-04 11:30:02 +0200796 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (err)
798 return err;
799
Jeff Dike84b3db02007-10-16 01:27:13 -0700800 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 attr->ia_valid &= ~ATTR_SIZE;
802
803 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 attrs.ia_valid |= HOSTFS_ATTR_MODE;
806 attrs.ia_mode = attr->ia_mode;
807 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 attrs.ia_valid |= HOSTFS_ATTR_UID;
810 attrs.ia_uid = attr->ia_uid;
811 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 attrs.ia_valid |= HOSTFS_ATTR_GID;
814 attrs.ia_gid = attr->ia_gid;
815 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
818 attrs.ia_size = attr->ia_size;
819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
822 attrs.ia_atime = attr->ia_atime;
823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
826 attrs.ia_mtime = attr->ia_mtime;
827 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
830 attrs.ia_ctime = attr->ia_ctime;
831 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700832 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
837 }
Al Viroc5322222010-06-06 20:42:10 -0400838 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700840 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700841 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400842 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700844 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Christoph Hellwig10257742010-06-04 11:30:02 +0200846 if ((attr->ia_valid & ATTR_SIZE) &&
847 attr->ia_size != i_size_read(inode)) {
848 int error;
849
850 error = vmtruncate(inode, attr->ia_size);
851 if (err)
852 return err;
853 }
854
855 setattr_copy(inode, attr);
856 mark_inode_dirty(inode);
857 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
859
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800860static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 .create = hostfs_create,
862 .link = hostfs_link,
863 .unlink = hostfs_unlink,
864 .symlink = hostfs_symlink,
865 .mkdir = hostfs_mkdir,
866 .rmdir = hostfs_rmdir,
867 .mknod = hostfs_mknod,
868 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 .permission = hostfs_permission,
870 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871};
872
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800873static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 .create = hostfs_create,
875 .lookup = hostfs_lookup,
876 .link = hostfs_link,
877 .unlink = hostfs_unlink,
878 .symlink = hostfs_symlink,
879 .mkdir = hostfs_mkdir,
880 .rmdir = hostfs_rmdir,
881 .mknod = hostfs_mknod,
882 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 .permission = hostfs_permission,
884 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885};
886
Al Virod0352d32010-06-06 21:51:16 -0400887static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Al Virod0352d32010-06-06 21:51:16 -0400889 char *link = __getname();
890 if (link) {
891 char *path = dentry_name(dentry);
892 int err = -ENOMEM;
893 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400894 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400895 if (err == PATH_MAX)
896 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400897 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400898 }
899 if (err < 0) {
900 __putname(link);
901 link = ERR_PTR(err);
902 }
903 } else {
904 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Al Virod0352d32010-06-06 21:51:16 -0400906
907 nd_set_link(nd, link);
908 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909}
910
Al Virod0352d32010-06-06 21:51:16 -0400911static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
912{
913 char *s = nd_get_link(nd);
914 if (!IS_ERR(s))
915 __putname(s);
916}
917
918static const struct inode_operations hostfs_link_iops = {
919 .readlink = generic_readlink,
920 .follow_link = hostfs_follow_link,
921 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922};
923
924static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
925{
926 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700927 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 int err;
929
930 sb->s_blocksize = 1024;
931 sb->s_blocksize_bits = 10;
932 sb->s_magic = HOSTFS_SUPER_MAGIC;
933 sb->s_op = &hostfs_sbops;
Al Virof772c4a2011-01-12 16:47:00 -0500934 sb->s_d_op = &hostfs_dentry_ops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700935 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800937 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700938 if (req_root == NULL)
939 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400942 sb->s_fs_info = host_root_path =
943 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700944 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 goto out;
946
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700947 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Al Viro52b209f2010-06-06 18:43:19 -0400949 root_inode = new_inode(sb);
950 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400951 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Al Viro4754b822010-06-06 20:33:12 -0400953 err = read_name(root_inode, host_root_path);
954 if (err)
955 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400956
Al Viro4754b822010-06-06 20:33:12 -0400957 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400958 char *name = follow_link(host_root_path);
959 if (IS_ERR(name))
960 err = PTR_ERR(name);
961 else
962 err = read_name(root_inode, name);
963 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400964 if (err)
965 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 err = -ENOMEM;
969 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700970 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 goto out_put;
972
Jeff Dikef1adc052007-05-08 00:23:18 -0700973 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Jeff Dikef1adc052007-05-08 00:23:18 -0700975out_put:
976 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700977out:
978 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
Al Viro3c26ff62010-07-25 11:46:36 +0400981static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700982 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400983 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984{
Al Viro3c26ff62010-07-25 11:46:36 +0400985 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986}
987
Al Viro601d2c32010-06-06 17:53:01 -0400988static void hostfs_kill_sb(struct super_block *s)
989{
990 kill_anon_super(s);
991 kfree(s->s_fs_info);
992}
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994static struct file_system_type hostfs_type = {
995 .owner = THIS_MODULE,
996 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400997 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400998 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 .fs_flags = 0,
1000};
1001
1002static int __init init_hostfs(void)
1003{
Jeff Dikef1adc052007-05-08 00:23:18 -07001004 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
1007static void __exit exit_hostfs(void)
1008{
1009 unregister_filesystem(&hostfs_type);
1010}
1011
1012module_init(init_hostfs)
1013module_exit(exit_hostfs)
1014MODULE_LICENSE("GPL");