blob: 2638c834ed281db783f6a7cd5ef24e2edb2047e4 [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 Pigginfa0d7e3d2011-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 Pigginfa0d7e3d2011-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
Al Viroc5322222010-06-06 20:42:10 -0400686 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400689 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691}
692
693int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
694{
695 struct inode *inode;
696 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800697 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
David Howells0a370e52008-02-07 00:15:50 -0800699 inode = hostfs_iget(dir->i_sb);
700 if (IS_ERR(inode)) {
701 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400706 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700707 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 goto out_put;
709
710 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800711 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400712 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 goto out_free;
714
715 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400716 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400717 if (err)
718 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700719 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 goto out_put;
721
722 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700723 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400726 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 out_put:
728 iput(inode);
729 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700730 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
733int hostfs_rename(struct inode *from_ino, struct dentry *from,
734 struct inode *to_ino, struct dentry *to)
735{
736 char *from_name, *to_name;
737 int err;
738
Al Viroc5322222010-06-06 20:42:10 -0400739 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400741 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400742 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700743 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 }
745 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400746 __putname(from_name);
747 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749}
750
Nick Pigginb74c79e2011-01-07 17:49:58 +1100751int hostfs_permission(struct inode *ino, int desired, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
753 char *name;
754 int r = 0, w = 0, x = 0, err;
755
Nick Pigginb74c79e2011-01-07 17:49:58 +1100756 if (flags & IPERM_FLAG_RCU)
757 return -ECHILD;
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (desired & MAY_READ) r = 1;
760 if (desired & MAY_WRITE) w = 1;
761 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400762 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700763 if (name == NULL)
764 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700767 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 err = 0;
769 else
770 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400771 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700772 if (!err)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100773 err = generic_permission(ino, desired, flags, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return err;
775}
776
777int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
778{
Christoph Hellwig10257742010-06-04 11:30:02 +0200779 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 struct hostfs_iattr attrs;
781 char *name;
782 int err;
783
Christoph Hellwig10257742010-06-04 11:30:02 +0200784 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700785
Christoph Hellwig10257742010-06-04 11:30:02 +0200786 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (err)
788 return err;
789
Jeff Dike84b3db02007-10-16 01:27:13 -0700790 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 attr->ia_valid &= ~ATTR_SIZE;
792
793 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 attrs.ia_valid |= HOSTFS_ATTR_MODE;
796 attrs.ia_mode = attr->ia_mode;
797 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700798 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 attrs.ia_valid |= HOSTFS_ATTR_UID;
800 attrs.ia_uid = attr->ia_uid;
801 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700802 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 attrs.ia_valid |= HOSTFS_ATTR_GID;
804 attrs.ia_gid = attr->ia_gid;
805 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700806 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
808 attrs.ia_size = attr->ia_size;
809 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700810 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
812 attrs.ia_atime = attr->ia_atime;
813 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700814 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
816 attrs.ia_mtime = attr->ia_mtime;
817 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700818 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
820 attrs.ia_ctime = attr->ia_ctime;
821 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700822 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
824 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
827 }
Al Viroc5322222010-06-06 20:42:10 -0400828 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700830 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700831 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400832 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700834 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Christoph Hellwig10257742010-06-04 11:30:02 +0200836 if ((attr->ia_valid & ATTR_SIZE) &&
837 attr->ia_size != i_size_read(inode)) {
838 int error;
839
840 error = vmtruncate(inode, attr->ia_size);
841 if (err)
842 return err;
843 }
844
845 setattr_copy(inode, attr);
846 mark_inode_dirty(inode);
847 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800850static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 .create = hostfs_create,
852 .link = hostfs_link,
853 .unlink = hostfs_unlink,
854 .symlink = hostfs_symlink,
855 .mkdir = hostfs_mkdir,
856 .rmdir = hostfs_rmdir,
857 .mknod = hostfs_mknod,
858 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 .permission = hostfs_permission,
860 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861};
862
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800863static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 .create = hostfs_create,
865 .lookup = hostfs_lookup,
866 .link = hostfs_link,
867 .unlink = hostfs_unlink,
868 .symlink = hostfs_symlink,
869 .mkdir = hostfs_mkdir,
870 .rmdir = hostfs_rmdir,
871 .mknod = hostfs_mknod,
872 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .permission = hostfs_permission,
874 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875};
876
Al Virod0352d32010-06-06 21:51:16 -0400877static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
Al Virod0352d32010-06-06 21:51:16 -0400879 char *link = __getname();
880 if (link) {
881 char *path = dentry_name(dentry);
882 int err = -ENOMEM;
883 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400884 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400885 if (err == PATH_MAX)
886 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400887 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400888 }
889 if (err < 0) {
890 __putname(link);
891 link = ERR_PTR(err);
892 }
893 } else {
894 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 }
Al Virod0352d32010-06-06 21:51:16 -0400896
897 nd_set_link(nd, link);
898 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899}
900
Al Virod0352d32010-06-06 21:51:16 -0400901static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
902{
903 char *s = nd_get_link(nd);
904 if (!IS_ERR(s))
905 __putname(s);
906}
907
908static const struct inode_operations hostfs_link_iops = {
909 .readlink = generic_readlink,
910 .follow_link = hostfs_follow_link,
911 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912};
913
914static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
915{
916 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700917 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 int err;
919
920 sb->s_blocksize = 1024;
921 sb->s_blocksize_bits = 10;
922 sb->s_magic = HOSTFS_SUPER_MAGIC;
923 sb->s_op = &hostfs_sbops;
Al Virof772c4a2011-01-12 16:47:00 -0500924 sb->s_d_op = &hostfs_dentry_ops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700925 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800927 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700928 if (req_root == NULL)
929 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400932 sb->s_fs_info = host_root_path =
933 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700934 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 goto out;
936
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700937 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Al Viro52b209f2010-06-06 18:43:19 -0400939 root_inode = new_inode(sb);
940 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400941 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Al Viro4754b822010-06-06 20:33:12 -0400943 err = read_name(root_inode, host_root_path);
944 if (err)
945 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400946
Al Viro4754b822010-06-06 20:33:12 -0400947 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400948 char *name = follow_link(host_root_path);
949 if (IS_ERR(name))
950 err = PTR_ERR(name);
951 else
952 err = read_name(root_inode, name);
953 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400954 if (err)
955 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 err = -ENOMEM;
959 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700960 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 goto out_put;
962
Jeff Dikef1adc052007-05-08 00:23:18 -0700963 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Jeff Dikef1adc052007-05-08 00:23:18 -0700965out_put:
966 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700967out:
968 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
Al Viro3c26ff62010-07-25 11:46:36 +0400971static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700972 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400973 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Al Viro3c26ff62010-07-25 11:46:36 +0400975 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976}
977
Al Viro601d2c32010-06-06 17:53:01 -0400978static void hostfs_kill_sb(struct super_block *s)
979{
980 kill_anon_super(s);
981 kfree(s->s_fs_info);
982}
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984static struct file_system_type hostfs_type = {
985 .owner = THIS_MODULE,
986 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400987 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400988 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 .fs_flags = 0,
990};
991
992static int __init init_hostfs(void)
993{
Jeff Dikef1adc052007-05-08 00:23:18 -0700994 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
997static void __exit exit_hostfs(void)
998{
999 unregister_filesystem(&hostfs_type);
1000}
1001
1002module_init(init_hostfs)
1003module_exit(exit_hostfs)
1004MODULE_LICENSE("GPL");