blob: e6816b9e6903e0d80d4ab7505ad84b276ec12baa [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);
253 INIT_LIST_HEAD(&inode->i_dentry);
254 kfree(HOSTFS_I(inode));
255}
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257static void hostfs_destroy_inode(struct inode *inode)
258{
Nick Pigginfa0d7e32011-01-07 17:49:49 +1100259 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260}
261
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
263{
Al Viro601d2c32010-06-06 17:53:01 -0400264 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800265 size_t offset = strlen(root_ino) + 1;
266
267 if (strlen(root_path) > offset)
268 seq_printf(seq, ",%s", root_path + offset);
269
270 return 0;
271}
272
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800273static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400276 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800278 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279};
280
281int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
282{
283 void *dir;
284 char *name;
285 unsigned long long next, ino;
286 int error, len;
287
Al Viroc5322222010-06-06 20:42:10 -0400288 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400292 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700293 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700294 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700296 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 error = (*filldir)(ent, name, len, file->f_pos,
298 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700299 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 file->f_pos = next;
301 }
302 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700303 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304}
305
306int hostfs_file_open(struct inode *ino, struct file *file)
307{
Al Virof8ad8502010-06-06 23:49:18 -0400308 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400310 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400311 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400312 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700315 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700316 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Virof8ad8502010-06-06 23:49:18 -0400318 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Al Virof8ad8502010-06-06 23:49:18 -0400320retry:
321 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400323 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 r = 1;
327
Al Viroc5322222010-06-06 20:42:10 -0400328 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700329 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700330 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400333 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700334 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700335 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400336
337 mutex_lock(&open_mutex);
338 /* somebody else had handled it first? */
339 if ((mode & HOSTFS_I(ino)->mode) == mode) {
340 mutex_unlock(&open_mutex);
341 return 0;
342 }
343 if ((mode | HOSTFS_I(ino)->mode) != mode) {
344 mode |= HOSTFS_I(ino)->mode;
345 mutex_unlock(&open_mutex);
346 close_file(&fd);
347 goto retry;
348 }
349 if (HOSTFS_I(ino)->fd == -1) {
350 HOSTFS_I(ino)->fd = fd;
351 } else {
352 err = replace_file(fd, HOSTFS_I(ino)->fd);
353 close_file(&fd);
354 if (err < 0) {
355 mutex_unlock(&open_mutex);
356 return err;
357 }
358 }
359 HOSTFS_I(ino)->mode = mode;
360 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Jeff Dikef1adc052007-05-08 00:23:18 -0700362 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200365int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200367 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
369
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800370static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700372 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200373 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 .aio_read = generic_file_aio_read,
375 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700376 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 .mmap = generic_file_mmap,
378 .open = hostfs_file_open,
379 .release = NULL,
380 .fsync = hostfs_fsync,
381};
382
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800383static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 .llseek = generic_file_llseek,
385 .readdir = hostfs_readdir,
386 .read = generic_read_dir,
387};
388
389int hostfs_writepage(struct page *page, struct writeback_control *wbc)
390{
391 struct address_space *mapping = page->mapping;
392 struct inode *inode = mapping->host;
393 char *buffer;
394 unsigned long long base;
395 int count = PAGE_CACHE_SIZE;
396 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
397 int err;
398
399 if (page->index >= end_index)
400 count = inode->i_size & (PAGE_CACHE_SIZE-1);
401
402 buffer = kmap(page);
403 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
404
405 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700406 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 ClearPageUptodate(page);
408 goto out;
409 }
410
411 if (base > inode->i_size)
412 inode->i_size = base;
413
414 if (PageError(page))
415 ClearPageError(page);
416 err = 0;
417
418 out:
419 kunmap(page);
420
421 unlock_page(page);
422 return err;
423}
424
425int hostfs_readpage(struct file *file, struct page *page)
426{
427 char *buffer;
428 long long start;
429 int err = 0;
430
431 start = (long long) page->index << PAGE_CACHE_SHIFT;
432 buffer = kmap(page);
433 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
434 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700435 if (err < 0)
436 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
439
440 flush_dcache_page(page);
441 SetPageUptodate(page);
442 if (PageError(page)) ClearPageError(page);
443 err = 0;
444 out:
445 kunmap(page);
446 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700447 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
Nick Pigginae361ff2007-10-16 01:25:17 -0700450int hostfs_write_begin(struct file *file, struct address_space *mapping,
451 loff_t pos, unsigned len, unsigned flags,
452 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Nick Pigginae361ff2007-10-16 01:25:17 -0700454 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Nick Piggin54566b22009-01-04 12:00:53 -0800456 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700457 if (!*pagep)
458 return -ENOMEM;
459 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Nick Pigginae361ff2007-10-16 01:25:17 -0700462int hostfs_write_end(struct file *file, struct address_space *mapping,
463 loff_t pos, unsigned len, unsigned copied,
464 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700467 void *buffer;
468 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
469 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700472 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700474
475 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
476 SetPageUptodate(page);
477
Jeff Dike84b3db02007-10-16 01:27:13 -0700478 /*
479 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700480 * i_size against the last byte written.
481 */
482 if (err > 0 && (pos > inode->i_size))
483 inode->i_size = pos;
484 unlock_page(page);
485 page_cache_release(page);
486
Jeff Dikef1adc052007-05-08 00:23:18 -0700487 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700490static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 .writepage = hostfs_writepage,
492 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700493 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700494 .write_begin = hostfs_write_begin,
495 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496};
497
Al Viro4754b822010-06-06 20:33:12 -0400498static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Al Viro4754b822010-06-06 20:33:12 -0400500 dev_t rdev;
501 struct hostfs_stat st;
502 int err = stat_file(name, &st, -1);
503 if (err)
504 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Al Viro5e2df282010-06-06 19:38:18 -0400506 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400507 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Al Viro4754b822010-06-06 20:33:12 -0400509 switch (st.mode & S_IFMT) {
510 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400511 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400512 break;
513 case S_IFDIR:
514 ino->i_op = &hostfs_dir_iops;
515 ino->i_fop = &hostfs_dir_fops;
516 break;
517 case S_IFCHR:
518 case S_IFBLK:
519 case S_IFIFO:
520 case S_IFSOCK:
521 init_special_inode(ino, st.mode & S_IFMT, rdev);
522 ino->i_op = &hostfs_iops;
523 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Al Viro4754b822010-06-06 20:33:12 -0400525 default:
526 ino->i_op = &hostfs_iops;
527 ino->i_fop = &hostfs_file_fops;
528 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Al Viro4754b822010-06-06 20:33:12 -0400530
531 ino->i_ino = st.ino;
532 ino->i_mode = st.mode;
533 ino->i_nlink = st.nlink;
534 ino->i_uid = st.uid;
535 ino->i_gid = st.gid;
536 ino->i_atime = st.atime;
537 ino->i_mtime = st.mtime;
538 ino->i_ctime = st.ctime;
539 ino->i_size = st.size;
540 ino->i_blocks = st.blocks;
541 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542}
543
544int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700545 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 struct inode *inode;
548 char *name;
549 int error, fd;
550
David Howells0a370e52008-02-07 00:15:50 -0800551 inode = hostfs_iget(dir->i_sb);
552 if (IS_ERR(inode)) {
553 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700554 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400558 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700559 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 goto out_put;
561
562 fd = file_create(name,
563 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
564 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
565 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400566 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400568 else
Al Viro5e2df282010-06-06 19:38:18 -0400569 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Al Viroe9193052010-06-06 23:16:34 -0400571 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700572 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 goto out_put;
574
575 HOSTFS_I(inode)->fd = fd;
576 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
577 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700578 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 out_put:
581 iput(inode);
582 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700583 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700587 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 struct inode *inode;
590 char *name;
591 int err;
592
David Howells0a370e52008-02-07 00:15:50 -0800593 inode = hostfs_iget(ino->i_sb);
594 if (IS_ERR(inode)) {
595 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400600 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700601 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 goto out_put;
603
604 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400605
Al Viroe9193052010-06-06 23:16:34 -0400606 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700607 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 iput(inode);
609 inode = NULL;
610 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700615 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 out_put:
618 iput(inode);
619 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700620 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
624{
Jeff Dikef1adc052007-05-08 00:23:18 -0700625 char *from_name, *to_name;
626 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Al Viroc5322222010-06-06 20:42:10 -0400628 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700629 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400630 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700631 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400632 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400636 __putname(from_name);
637 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700638 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
641int hostfs_unlink(struct inode *ino, struct dentry *dentry)
642{
643 char *file;
644 int err;
645
Jeff Dike84b3db02007-10-16 01:27:13 -0700646 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700647 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Al Virof8d7e182010-06-06 23:19:04 -0400649 if ((file = dentry_name(dentry)) == NULL)
650 return -ENOMEM;
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400653 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
657int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
658{
659 char *file;
660 int err;
661
Al Viroc5322222010-06-06 20:42:10 -0400662 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700663 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400665 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
669int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
670{
671 char *file;
672 int err;
673
Al Viroc5322222010-06-06 20:42:10 -0400674 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700675 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400677 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
682{
683 char *file;
684 int err;
685
Sage Weil79bf7c72011-05-24 13:06:06 -0700686 dentry_unhash(dentry);
687
Al Viroc5322222010-06-06 20:42:10 -0400688 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700689 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400691 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700692 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693}
694
695int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
696{
697 struct inode *inode;
698 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800699 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
David Howells0a370e52008-02-07 00:15:50 -0800701 inode = hostfs_iget(dir->i_sb);
702 if (IS_ERR(inode)) {
703 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400708 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700709 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 goto out_put;
711
712 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800713 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400714 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 goto out_free;
716
717 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400718 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400719 if (err)
720 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700721 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 goto out_put;
723
724 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700725 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400728 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 out_put:
730 iput(inode);
731 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
735int hostfs_rename(struct inode *from_ino, struct dentry *from,
736 struct inode *to_ino, struct dentry *to)
737{
738 char *from_name, *to_name;
739 int err;
740
Sage Weile4eaac02011-05-24 13:06:07 -0700741 if (to->d_inode && S_ISDIR(to->d_inode->i_mode))
742 dentry_unhash(to);
743
Al Viroc5322222010-06-06 20:42:10 -0400744 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700745 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400746 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400747 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
750 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400751 __putname(from_name);
752 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700753 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754}
755
Nick Pigginb74c79e2011-01-07 17:49:58 +1100756int hostfs_permission(struct inode *ino, int desired, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
758 char *name;
759 int r = 0, w = 0, x = 0, err;
760
Nick Pigginb74c79e2011-01-07 17:49:58 +1100761 if (flags & IPERM_FLAG_RCU)
762 return -ECHILD;
763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (desired & MAY_READ) r = 1;
765 if (desired & MAY_WRITE) w = 1;
766 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400767 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700768 if (name == NULL)
769 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700772 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 err = 0;
774 else
775 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400776 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700777 if (!err)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100778 err = generic_permission(ino, desired, flags, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return err;
780}
781
782int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
783{
Christoph Hellwig10257742010-06-04 11:30:02 +0200784 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 struct hostfs_iattr attrs;
786 char *name;
787 int err;
788
Christoph Hellwig10257742010-06-04 11:30:02 +0200789 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700790
Christoph Hellwig10257742010-06-04 11:30:02 +0200791 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (err)
793 return err;
794
Jeff Dike84b3db02007-10-16 01:27:13 -0700795 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 attr->ia_valid &= ~ATTR_SIZE;
797
798 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700799 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 attrs.ia_valid |= HOSTFS_ATTR_MODE;
801 attrs.ia_mode = attr->ia_mode;
802 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700803 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 attrs.ia_valid |= HOSTFS_ATTR_UID;
805 attrs.ia_uid = attr->ia_uid;
806 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700807 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 attrs.ia_valid |= HOSTFS_ATTR_GID;
809 attrs.ia_gid = attr->ia_gid;
810 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700811 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
813 attrs.ia_size = attr->ia_size;
814 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
817 attrs.ia_atime = attr->ia_atime;
818 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
821 attrs.ia_mtime = attr->ia_mtime;
822 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
825 attrs.ia_ctime = attr->ia_ctime;
826 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
829 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700830 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
832 }
Al Viroc5322222010-06-06 20:42:10 -0400833 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700834 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700835 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700836 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400837 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700838 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700839 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Christoph Hellwig10257742010-06-04 11:30:02 +0200841 if ((attr->ia_valid & ATTR_SIZE) &&
842 attr->ia_size != i_size_read(inode)) {
843 int error;
844
845 error = vmtruncate(inode, attr->ia_size);
846 if (err)
847 return err;
848 }
849
850 setattr_copy(inode, attr);
851 mark_inode_dirty(inode);
852 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}
854
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800855static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 .create = hostfs_create,
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
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800868static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 .create = hostfs_create,
870 .lookup = hostfs_lookup,
871 .link = hostfs_link,
872 .unlink = hostfs_unlink,
873 .symlink = hostfs_symlink,
874 .mkdir = hostfs_mkdir,
875 .rmdir = hostfs_rmdir,
876 .mknod = hostfs_mknod,
877 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .permission = hostfs_permission,
879 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880};
881
Al Virod0352d32010-06-06 21:51:16 -0400882static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
Al Virod0352d32010-06-06 21:51:16 -0400884 char *link = __getname();
885 if (link) {
886 char *path = dentry_name(dentry);
887 int err = -ENOMEM;
888 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400889 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400890 if (err == PATH_MAX)
891 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400892 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400893 }
894 if (err < 0) {
895 __putname(link);
896 link = ERR_PTR(err);
897 }
898 } else {
899 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 }
Al Virod0352d32010-06-06 21:51:16 -0400901
902 nd_set_link(nd, link);
903 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904}
905
Al Virod0352d32010-06-06 21:51:16 -0400906static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
907{
908 char *s = nd_get_link(nd);
909 if (!IS_ERR(s))
910 __putname(s);
911}
912
913static const struct inode_operations hostfs_link_iops = {
914 .readlink = generic_readlink,
915 .follow_link = hostfs_follow_link,
916 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917};
918
919static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
920{
921 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700922 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int err;
924
925 sb->s_blocksize = 1024;
926 sb->s_blocksize_bits = 10;
927 sb->s_magic = HOSTFS_SUPER_MAGIC;
928 sb->s_op = &hostfs_sbops;
Al Virof772c4a2011-01-12 16:47:00 -0500929 sb->s_d_op = &hostfs_dentry_ops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700930 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800932 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700933 if (req_root == NULL)
934 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400937 sb->s_fs_info = host_root_path =
938 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700939 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 goto out;
941
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700942 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Al Viro52b209f2010-06-06 18:43:19 -0400944 root_inode = new_inode(sb);
945 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400946 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Al Viro4754b822010-06-06 20:33:12 -0400948 err = read_name(root_inode, host_root_path);
949 if (err)
950 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400951
Al Viro4754b822010-06-06 20:33:12 -0400952 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400953 char *name = follow_link(host_root_path);
954 if (IS_ERR(name))
955 err = PTR_ERR(name);
956 else
957 err = read_name(root_inode, name);
958 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400959 if (err)
960 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 err = -ENOMEM;
964 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700965 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 goto out_put;
967
Jeff Dikef1adc052007-05-08 00:23:18 -0700968 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Jeff Dikef1adc052007-05-08 00:23:18 -0700970out_put:
971 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700972out:
973 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
Al Viro3c26ff62010-07-25 11:46:36 +0400976static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700977 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400978 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Al Viro3c26ff62010-07-25 11:46:36 +0400980 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981}
982
Al Viro601d2c32010-06-06 17:53:01 -0400983static void hostfs_kill_sb(struct super_block *s)
984{
985 kill_anon_super(s);
986 kfree(s->s_fs_info);
987}
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989static struct file_system_type hostfs_type = {
990 .owner = THIS_MODULE,
991 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400992 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400993 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 .fs_flags = 0,
995};
996
997static int __init init_hostfs(void)
998{
Jeff Dikef1adc052007-05-08 00:23:18 -0700999 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000}
1001
1002static void __exit exit_hostfs(void)
1003{
1004 unregister_filesystem(&hostfs_type);
1005}
1006
1007module_init(init_hostfs)
1008module_exit(exit_hostfs)
1009MODULE_LICENSE("GPL");