Blame view

fs/hostfs/hostfs_kern.c 20.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
f1adc05e7   Jeff Dike   uml: hostfs style...
2
   * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
   * Licensed under the GPL
   *
   * Ported the filesystem routines to 2.5.
   * 2003-02-10 Petr Baudis <pasky@ucw.cz>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/fs.h>
2b3b9bb03   James Hogan   hostfs: move HOST...
9
  #include <linux/magic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include <linux/module.h>
84b3db04c   Jeff Dike   uml: fix hostfs s...
11
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/statfs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
dd2cc4dff   Miklos Szeredi   mount options: fi...
15
  #include <linux/seq_file.h>
6966a9775   Jiri Kosina   UML: fix hostfs b...
16
  #include <linux/mount.h>
d0352d3ed   Al Viro   hostfs: sanitize ...
17
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include "hostfs.h"
37185b332   Al Viro   um: get rid of po...
19
20
  #include <init.h>
  #include <kern.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  
  struct hostfs_inode_info {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  	int fd;
aeb5d7270   Al Viro   [PATCH] introduce...
24
  	fmode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  	struct inode vfs_inode;
69886e676   Richard Weinberger   hostfs: hostfs_fi...
26
  	struct mutex open_mutex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  };
  
  static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
31
  	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  }
496ad9aa8   Al Viro   new helper: file_...
33
  #define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  /* Changed in hostfs_args before the kernel starts running */
a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
36
  static char *root_ino = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  static int append = 0;
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
38
39
  static const struct inode_operations hostfs_iops;
  static const struct inode_operations hostfs_dir_iops;
d0352d3ed   Al Viro   hostfs: sanitize ...
40
  static const struct inode_operations hostfs_link_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
  
  #ifndef MODULE
  static int __init hostfs_args(char *options, int *add)
  {
  	char *ptr;
  
  	ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
48
  	if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  		*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
50
  	if (*options != '\0')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
  		root_ino = options;
  
  	options = ptr;
84b3db04c   Jeff Dike   uml: fix hostfs s...
54
  	while (options) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  		ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
56
  		if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  			*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
58
59
  		if (*options != '\0') {
  			if (!strcmp(options, "append"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
  				append = 1;
  			else printf("hostfs_args - unsupported option - %s
  ",
  				    options);
  		}
  		options = ptr;
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
67
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  }
  
  __uml_setup("hostfs=", hostfs_args,
  "hostfs=<root dir>,<flags>,...
  "
  "    This is used to set hostfs parameters.  The root directory argument
  "
  "    is used to confine all hostfs mounts to within the specified directory
  "
  "    tree on the host.  If this isn't specified, then a user inside UML can
  "
  "    mount anything on the host that's accessible to the user that's running
  "
  "    it.
  "
  "    The only flag currently supported is 'append', which specifies that all
  "
  "    files opened by hostfs will be opened in append mode.
  
  "
  );
  #endif
e9193059b   Al Viro   hostfs: fix races...
90
  static char *__dentry_name(struct dentry *dentry, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  {
ec2447c27   Nick Piggin   hostfs: simplify ...
92
  	char *p = dentry_path_raw(dentry, name, PATH_MAX);
e9193059b   Al Viro   hostfs: fix races...
93
94
  	char *root;
  	size_t len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

e9193059b   Al Viro   hostfs: fix races...
96
97
98
99
  	root = dentry->d_sb->s_fs_info;
  	len = strlen(root);
  	if (IS_ERR(p)) {
  		__putname(name);
f1adc05e7   Jeff Dike   uml: hostfs style...
100
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	}
aad50b1e0   Richard Weinberger   hostfs: Add a BUG...
102
103
104
105
106
107
  
  	/*
  	 * This function relies on the fact that dentry_path_raw() will place
  	 * the path name at the end of the provided buffer.
  	 */
  	BUG_ON(p + strlen(p) + 1 != name + PATH_MAX);
850a496f9   Al Viro   hostfs: dumb (and...
108
  	strlcpy(name, root, PATH_MAX);
e9193059b   Al Viro   hostfs: fix races...
109
110
111
112
  	if (len > p - name) {
  		__putname(name);
  		return NULL;
  	}
c278e81b8   Richard Weinberger   hostfs: Remove op...
113
114
115
  
  	if (p > name + len)
  		strcpy(name + len, p);
f1adc05e7   Jeff Dike   uml: hostfs style...
116
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  }
e9193059b   Al Viro   hostfs: fix races...
118
119
120
121
122
  static char *dentry_name(struct dentry *dentry)
  {
  	char *name = __getname();
  	if (!name)
  		return NULL;
9dcc5e8a4   James Hogan   hostfs: remove "w...
123
  	return __dentry_name(dentry, name);
e9193059b   Al Viro   hostfs: fix races...
124
  }
c5322220e   Al Viro   hostfs: get rid o...
125
  static char *inode_name(struct inode *ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  {
  	struct dentry *dentry;
ec2447c27   Nick Piggin   hostfs: simplify ...
128
  	char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

ec2447c27   Nick Piggin   hostfs: simplify ...
130
131
  	dentry = d_find_alias(ino);
  	if (!dentry)
e9193059b   Al Viro   hostfs: fix races...
132
  		return NULL;
ec2447c27   Nick Piggin   hostfs: simplify ...
133
134
135
136
137
138
  
  	name = dentry_name(dentry);
  
  	dput(dentry);
  
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  static char *follow_link(char *link)
  {
  	int len, n;
  	char *name, *resolved, *end;
7c9509924   Richard Weinberger   hostfs: Use __get...
144
145
  	name = __getname();
  	if (!name) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  		n = -ENOMEM;
7c9509924   Richard Weinberger   hostfs: Use __get...
147
  		goto out_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	}
7c9509924   Richard Weinberger   hostfs: Use __get...
149
150
  
  	n = hostfs_do_readlink(link, name, PATH_MAX);
84b3db04c   Jeff Dike   uml: fix hostfs s...
151
  	if (n < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  		goto out_free;
7c9509924   Richard Weinberger   hostfs: Use __get...
153
154
155
156
  	else if (n == PATH_MAX) {
  		n = -E2BIG;
  		goto out_free;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157

84b3db04c   Jeff Dike   uml: fix hostfs s...
158
  	if (*name == '/')
f1adc05e7   Jeff Dike   uml: hostfs style...
159
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  
  	end = strrchr(link, '/');
84b3db04c   Jeff Dike   uml: fix hostfs s...
162
  	if (end == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
163
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
  
  	*(end + 1) = '\0';
  	len = strlen(link) + strlen(name) + 1;
  
  	resolved = kmalloc(len, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
169
  	if (resolved == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
  		n = -ENOMEM;
  		goto out_free;
  	}
  
  	sprintf(resolved, "%s%s", link, name);
7c9509924   Richard Weinberger   hostfs: Use __get...
175
  	__putname(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  	kfree(link);
f1adc05e7   Jeff Dike   uml: hostfs style...
177
  	return resolved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  
   out_free:
7c9509924   Richard Weinberger   hostfs: Use __get...
180
  	__putname(name);
f1adc05e7   Jeff Dike   uml: hostfs style...
181
  	return ERR_PTR(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  }
0a370e5de   David Howells   iget: stop HOSTFS...
183
184
  static struct inode *hostfs_iget(struct super_block *sb)
  {
52b209f7b   Al Viro   get rid of hostfs...
185
  	struct inode *inode = new_inode(sb);
0a370e5de   David Howells   iget: stop HOSTFS...
186
187
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
0a370e5de   David Howells   iget: stop HOSTFS...
188
189
  	return inode;
  }
9e443bc36   James Hogan   um: hostfs: make ...
190
  static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  {
84b3db04c   Jeff Dike   uml: fix hostfs s...
192
193
  	/*
  	 * do_statfs uses struct statfs64 internally, but the linux kernel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
  	 * struct statfs still has 32-bit versions for most of these fields,
  	 * so we convert them here
  	 */
  	int err;
  	long long f_blocks;
  	long long f_bfree;
  	long long f_bavail;
  	long long f_files;
  	long long f_ffree;
601d2c38b   Al Viro   hostfs: don't kee...
203
  	err = do_statfs(dentry->d_sb->s_fs_info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
  			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
1b627d577   Richard Weinberger   hostfs: fix UML c...
206
  			&sf->f_namelen);
84b3db04c   Jeff Dike   uml: fix hostfs s...
207
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
208
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
  	sf->f_blocks = f_blocks;
  	sf->f_bfree = f_bfree;
  	sf->f_bavail = f_bavail;
  	sf->f_files = f_files;
  	sf->f_ffree = f_ffree;
  	sf->f_type = HOSTFS_SUPER_MAGIC;
f1adc05e7   Jeff Dike   uml: hostfs style...
215
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
  }
  
  static struct inode *hostfs_alloc_inode(struct super_block *sb)
  {
  	struct hostfs_inode_info *hi;
5d097056c   Vladimir Davydov   kmemcg: account c...
221
  	hi = kmalloc(sizeof(*hi), GFP_KERNEL_ACCOUNT);
84b3db04c   Jeff Dike   uml: fix hostfs s...
222
  	if (hi == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
223
  		return NULL;
601d2c38b   Al Viro   hostfs: don't kee...
224
  	hi->fd = -1;
371fdab10   James Hogan   hostfs: use kmall...
225
  	hi->mode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  	inode_init_once(&hi->vfs_inode);
69886e676   Richard Weinberger   hostfs: hostfs_fi...
227
  	mutex_init(&hi->open_mutex);
f1adc05e7   Jeff Dike   uml: hostfs style...
228
  	return &hi->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  }
e971a6d7b   Al Viro   stop icache pollu...
230
  static void hostfs_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
91b0abe36   Johannes Weiner   mm + fs: store sh...
232
  	truncate_inode_pages_final(&inode->i_data);
dbd5768f8   Jan Kara   vfs: Rename end_w...
233
  	clear_inode(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
234
  	if (HOSTFS_I(inode)->fd != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  		close_file(&HOSTFS_I(inode)->fd);
  		HOSTFS_I(inode)->fd = -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  }
08ccfc5c3   Al Viro   hostfs: switch to...
239
  static void hostfs_free_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  	kfree(HOSTFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
243

34c80b1d9   Al Viro   vfs: switch ->sho...
244
  static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
dd2cc4dff   Miklos Szeredi   mount options: fi...
245
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
246
  	const char *root_path = root->d_sb->s_fs_info;
dd2cc4dff   Miklos Szeredi   mount options: fi...
247
248
249
  	size_t offset = strlen(root_ino) + 1;
  
  	if (strlen(root_path) > offset)
a068acf2e   Kees Cook   fs: create and us...
250
  		seq_show_option(seq, root_path + offset, NULL);
dd2cc4dff   Miklos Szeredi   mount options: fi...
251

7f74a6687   Richard Weinberger   hostfs: Report ap...
252
253
  	if (append)
  		seq_puts(seq, ",append");
dd2cc4dff   Miklos Szeredi   mount options: fi...
254
255
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
256
  static const struct super_operations hostfs_sbops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	.alloc_inode	= hostfs_alloc_inode,
08ccfc5c3   Al Viro   hostfs: switch to...
258
  	.free_inode	= hostfs_free_inode,
e971a6d7b   Al Viro   stop icache pollu...
259
  	.evict_inode	= hostfs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  	.statfs		= hostfs_statfs,
dd2cc4dff   Miklos Szeredi   mount options: fi...
261
  	.show_options	= hostfs_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  };
9e443bc36   James Hogan   um: hostfs: make ...
263
  static int hostfs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
  {
  	void *dir;
  	char *name;
  	unsigned long long next, ino;
  	int error, len;
3ee6bd8e8   Geert Uytterhoeven   uml/hostfs: Propa...
269
  	unsigned int type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

c5322220e   Al Viro   hostfs: get rid o...
271
  	name = dentry_name(file->f_path.dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
272
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
273
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	dir = open_dir(name, &error);
e9193059b   Al Viro   hostfs: fix races...
275
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
276
  	if (dir == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
277
  		return -error;
8e28bc7e7   Al Viro   [readdir] convert...
278
  	next = ctx->pos;
0c9bd6365   Richard Weinberger   um: hostfs: Reduc...
279
  	seek_dir(dir, next);
3ee6bd8e8   Geert Uytterhoeven   uml/hostfs: Propa...
280
  	while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
8e28bc7e7   Al Viro   [readdir] convert...
281
282
283
  		if (!dir_emit(ctx, name, len, ino, type))
  			break;
  		ctx->pos = next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  	}
  	close_dir(dir);
f1adc05e7   Jeff Dike   uml: hostfs style...
286
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  }
4c6dcafc6   Richard Weinberger   hostfs: Allow fsy...
288
  static int hostfs_open(struct inode *ino, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  {
  	char *name;
bd1052a24   Richard Weinberger   hostfs: Remove su...
291
  	fmode_t mode;
f8ad850f1   Al Viro   try to get rid of...
292
  	int err;
bd1052a24   Richard Weinberger   hostfs: Remove su...
293
  	int r, w, fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  
  	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
84b3db04c   Jeff Dike   uml: fix hostfs s...
296
  	if ((mode & HOSTFS_I(ino)->mode) == mode)
f1adc05e7   Jeff Dike   uml: hostfs style...
297
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298

f8ad850f1   Al Viro   try to get rid of...
299
  	mode |= HOSTFS_I(ino)->mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

f8ad850f1   Al Viro   try to get rid of...
301
  retry:
a9d1958b4   Richard Weinberger   hostfs: hostfs_op...
302
  	r = w = 0;
f8ad850f1   Al Viro   try to get rid of...
303
  	if (mode & FMODE_READ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  		r = 1;
f8ad850f1   Al Viro   try to get rid of...
305
  	if (mode & FMODE_WRITE)
112a5da71   Richard Weinberger   hostfs: Remove su...
306
  		r = w = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307

c5322220e   Al Viro   hostfs: get rid o...
308
  	name = dentry_name(file->f_path.dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
309
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
310
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
  
  	fd = open_file(name, r, w, append);
e9193059b   Al Viro   hostfs: fix races...
313
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
314
  	if (fd < 0)
f1adc05e7   Jeff Dike   uml: hostfs style...
315
  		return fd;
f8ad850f1   Al Viro   try to get rid of...
316

69886e676   Richard Weinberger   hostfs: hostfs_fi...
317
  	mutex_lock(&HOSTFS_I(ino)->open_mutex);
f8ad850f1   Al Viro   try to get rid of...
318
319
  	/* somebody else had handled it first? */
  	if ((mode & HOSTFS_I(ino)->mode) == mode) {
69886e676   Richard Weinberger   hostfs: hostfs_fi...
320
  		mutex_unlock(&HOSTFS_I(ino)->open_mutex);
af9556586   Richard Weinberger   hostfs: hostfs_fi...
321
  		close_file(&fd);
f8ad850f1   Al Viro   try to get rid of...
322
323
324
325
  		return 0;
  	}
  	if ((mode | HOSTFS_I(ino)->mode) != mode) {
  		mode |= HOSTFS_I(ino)->mode;
69886e676   Richard Weinberger   hostfs: hostfs_fi...
326
  		mutex_unlock(&HOSTFS_I(ino)->open_mutex);
f8ad850f1   Al Viro   try to get rid of...
327
328
329
330
331
332
333
334
335
  		close_file(&fd);
  		goto retry;
  	}
  	if (HOSTFS_I(ino)->fd == -1) {
  		HOSTFS_I(ino)->fd = fd;
  	} else {
  		err = replace_file(fd, HOSTFS_I(ino)->fd);
  		close_file(&fd);
  		if (err < 0) {
69886e676   Richard Weinberger   hostfs: hostfs_fi...
336
  			mutex_unlock(&HOSTFS_I(ino)->open_mutex);
f8ad850f1   Al Viro   try to get rid of...
337
338
339
340
  			return err;
  		}
  	}
  	HOSTFS_I(ino)->mode = mode;
69886e676   Richard Weinberger   hostfs: hostfs_fi...
341
  	mutex_unlock(&HOSTFS_I(ino)->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342

f1adc05e7   Jeff Dike   uml: hostfs style...
343
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  }
65984ff9d   Richard Weinberger   um: hostfs: Fix w...
345
346
347
348
349
350
  static int hostfs_file_release(struct inode *inode, struct file *file)
  {
  	filemap_write_and_wait(inode->i_mapping);
  
  	return 0;
  }
9e443bc36   James Hogan   um: hostfs: make ...
351
352
  static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
  			int datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  {
02c24a821   Josef Bacik   fs: push i_mutex ...
354
355
  	struct inode *inode = file->f_mapping->host;
  	int ret;
3b49c9a1e   Jeff Layton   fs: convert a pil...
356
  	ret = file_write_and_wait_range(file, start, end);
02c24a821   Josef Bacik   fs: push i_mutex ...
357
358
  	if (ret)
  		return ret;
5955102c9   Al Viro   wrappers for ->i_...
359
  	inode_lock(inode);
02c24a821   Josef Bacik   fs: push i_mutex ...
360
  	ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
5955102c9   Al Viro   wrappers for ->i_...
361
  	inode_unlock(inode);
02c24a821   Josef Bacik   fs: push i_mutex ...
362
363
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
365
  static const struct file_operations hostfs_file_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	.llseek		= generic_file_llseek,
5ffc4ef45   Jens Axboe   sendfile: remove ...
367
  	.splice_read	= generic_file_splice_read,
aad4f8bb4   Al Viro   switch simple gen...
368
  	.read_iter	= generic_file_read_iter,
8174202b3   Al Viro   write_iter varian...
369
  	.write_iter	= generic_file_write_iter,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	.mmap		= generic_file_mmap,
4c6dcafc6   Richard Weinberger   hostfs: Allow fsy...
371
  	.open		= hostfs_open,
65984ff9d   Richard Weinberger   um: hostfs: Fix w...
372
  	.release	= hostfs_file_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
  	.fsync		= hostfs_fsync,
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
375
  static const struct file_operations hostfs_dir_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	.llseek		= generic_file_llseek,
552a9d489   Al Viro   hostfs: switch to...
377
  	.iterate_shared	= hostfs_readdir,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  	.read		= generic_read_dir,
4c6dcafc6   Richard Weinberger   hostfs: Allow fsy...
379
380
  	.open		= hostfs_open,
  	.fsync		= hostfs_fsync,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  };
9e443bc36   James Hogan   um: hostfs: make ...
382
  static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
386
  {
  	struct address_space *mapping = page->mapping;
  	struct inode *inode = mapping->host;
  	char *buffer;
af6aa1b9c   Richard Weinberger   hostfs: Use page_...
387
  	loff_t base = page_offset(page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
388
389
  	int count = PAGE_SIZE;
  	int end_index = inode->i_size >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
  	int err;
  
  	if (page->index >= end_index)
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
393
  		count = inode->i_size & (PAGE_SIZE-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
  
  	buffer = kmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
  
  	err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
84b3db04c   Jeff Dike   uml: fix hostfs s...
398
  	if (err != count) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  		ClearPageUptodate(page);
  		goto out;
  	}
  
  	if (base > inode->i_size)
  		inode->i_size = base;
  
  	if (PageError(page))
  		ClearPageError(page);
  	err = 0;
  
   out:
  	kunmap(page);
  
  	unlock_page(page);
  	return err;
  }
9e443bc36   James Hogan   um: hostfs: make ...
416
  static int hostfs_readpage(struct file *file, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  {
  	char *buffer;
af6aa1b9c   Richard Weinberger   hostfs: Use page_...
419
  	loff_t start = page_offset(page);
b86b413a3   Richard Weinberger   hostfs: Set page ...
420
  	int bytes_read, ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  	buffer = kmap(page);
41761ddfa   Richard Weinberger   hostfs: Make host...
423
  	bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
424
  			PAGE_SIZE);
41761ddfa   Richard Weinberger   hostfs: Make host...
425
  	if (bytes_read < 0) {
b86b413a3   Richard Weinberger   hostfs: Set page ...
426
427
  		ClearPageUptodate(page);
  		SetPageError(page);
41761ddfa   Richard Weinberger   hostfs: Make host...
428
  		ret = bytes_read;
84b3db04c   Jeff Dike   uml: fix hostfs s...
429
  		goto out;
41761ddfa   Richard Weinberger   hostfs: Make host...
430
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431

09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
432
  	memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433

b86b413a3   Richard Weinberger   hostfs: Set page ...
434
  	ClearPageError(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  	SetPageUptodate(page);
b86b413a3   Richard Weinberger   hostfs: Set page ...
436

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
   out:
b86b413a3   Richard Weinberger   hostfs: Set page ...
438
  	flush_dcache_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	kunmap(page);
  	unlock_page(page);
41761ddfa   Richard Weinberger   hostfs: Make host...
441
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  }
9e443bc36   James Hogan   um: hostfs: make ...
443
444
445
  static int hostfs_write_begin(struct file *file, struct address_space *mapping,
  			      loff_t pos, unsigned len, unsigned flags,
  			      struct page **pagep, void **fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  {
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
447
  	pgoff_t index = pos >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448

54566b2c1   Nick Piggin   fs: symlink write...
449
  	*pagep = grab_cache_page_write_begin(mapping, index, flags);
ae361ff46   Nick Piggin   hostfs: convert t...
450
451
452
  	if (!*pagep)
  		return -ENOMEM;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  }
9e443bc36   James Hogan   um: hostfs: make ...
454
455
456
  static int hostfs_write_end(struct file *file, struct address_space *mapping,
  			    loff_t pos, unsigned len, unsigned copied,
  			    struct page *page, void *fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  	struct inode *inode = mapping->host;
ae361ff46   Nick Piggin   hostfs: convert t...
459
  	void *buffer;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
460
  	unsigned from = pos & (PAGE_SIZE - 1);
ae361ff46   Nick Piggin   hostfs: convert t...
461
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  	buffer = kmap(page);
ae361ff46   Nick Piggin   hostfs: convert t...
464
465
  	err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
  	kunmap(page);
30f04a4ef   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
466

09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
467
  	if (!PageUptodate(page) && err == PAGE_SIZE)
ae361ff46   Nick Piggin   hostfs: convert t...
468
  		SetPageUptodate(page);
30f04a4ef   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
469

84b3db04c   Jeff Dike   uml: fix hostfs s...
470
471
  	/*
  	 * If err > 0, write_file has added err to pos, so we are comparing
ae361ff46   Nick Piggin   hostfs: convert t...
472
473
474
475
476
  	 * i_size against the last byte written.
  	 */
  	if (err > 0 && (pos > inode->i_size))
  		inode->i_size = pos;
  	unlock_page(page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
477
  	put_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478

f1adc05e7   Jeff Dike   uml: hostfs style...
479
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
481
  static const struct address_space_operations hostfs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  	.writepage 	= hostfs_writepage,
  	.readpage	= hostfs_readpage,
ffa0aea68   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml - hos...
484
  	.set_page_dirty = __set_page_dirty_nobuffers,
ae361ff46   Nick Piggin   hostfs: convert t...
485
486
  	.write_begin	= hostfs_write_begin,
  	.write_end	= hostfs_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  };
4754b8255   Al Viro   hostfs: get rid o...
488
  static int read_name(struct inode *ino, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  {
4754b8255   Al Viro   hostfs: get rid o...
490
491
492
493
494
  	dev_t rdev;
  	struct hostfs_stat st;
  	int err = stat_file(name, &st, -1);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495

5e2df28cc   Al Viro   hostfs: pass path...
496
  	/* Reencode maj and min with the kernel encoding.*/
4754b8255   Al Viro   hostfs: get rid o...
497
  	rdev = MKDEV(st.maj, st.min);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498

4754b8255   Al Viro   hostfs: get rid o...
499
500
  	switch (st.mode & S_IFMT) {
  	case S_IFLNK:
d0352d3ed   Al Viro   hostfs: sanitize ...
501
  		ino->i_op = &hostfs_link_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  		break;
4754b8255   Al Viro   hostfs: get rid o...
503
504
505
  	case S_IFDIR:
  		ino->i_op = &hostfs_dir_iops;
  		ino->i_fop = &hostfs_dir_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  		break;
4754b8255   Al Viro   hostfs: get rid o...
507
508
509
510
511
512
  	case S_IFCHR:
  	case S_IFBLK:
  	case S_IFIFO:
  	case S_IFSOCK:
  		init_special_inode(ino, st.mode & S_IFMT, rdev);
  		ino->i_op = &hostfs_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  		break;
2ad2dca6f   Richard Weinberger   hostfs: Handle bo...
514
  	case S_IFREG:
4754b8255   Al Viro   hostfs: get rid o...
515
516
517
  		ino->i_op = &hostfs_iops;
  		ino->i_fop = &hostfs_file_fops;
  		ino->i_mapping->a_ops = &hostfs_aops;
2ad2dca6f   Richard Weinberger   hostfs: Handle bo...
518
519
520
  		break;
  	default:
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  	}
4754b8255   Al Viro   hostfs: get rid o...
522
523
524
  
  	ino->i_ino = st.ino;
  	ino->i_mode = st.mode;
bfe868486   Miklos Szeredi   filesystems: add ...
525
  	set_nlink(ino, st.nlink);
29f82ae56   Eric W. Biederman   userns: Convert h...
526
527
  	i_uid_write(ino, st.uid);
  	i_gid_write(ino, st.gid);
95582b008   Deepa Dinamani   vfs: change inode...
528
529
530
  	ino->i_atime = timespec_to_timespec64(st.atime);
  	ino->i_mtime = timespec_to_timespec64(st.mtime);
  	ino->i_ctime = timespec_to_timespec64(st.ctime);
4754b8255   Al Viro   hostfs: get rid o...
531
532
533
  	ino->i_size = st.size;
  	ino->i_blocks = st.blocks;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  }
9e443bc36   James Hogan   um: hostfs: make ...
535
536
  static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
  			 bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
  {
  	struct inode *inode;
  	char *name;
  	int error, fd;
0a370e5de   David Howells   iget: stop HOSTFS...
541
542
543
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
544
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
545
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  	error = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
548
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
549
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  		goto out_put;
a718c9221   Richard Weinberger   hostfs: Use corre...
551
  	fd = file_create(name, mode & 0777);
4754b8255   Al Viro   hostfs: get rid o...
552
  	if (fd < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  		error = fd;
4754b8255   Al Viro   hostfs: get rid o...
554
  	else
5e2df28cc   Al Viro   hostfs: pass path...
555
  		error = read_name(inode, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

e9193059b   Al Viro   hostfs: fix races...
557
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
558
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
  		goto out_put;
  
  	HOSTFS_I(inode)->fd = fd;
  	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
  	d_instantiate(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
564
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
569
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  }
9e443bc36   James Hogan   um: hostfs: make ...
571
572
  static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
  				    unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
  {
  	struct inode *inode;
  	char *name;
  	int err;
0a370e5de   David Howells   iget: stop HOSTFS...
577
  	inode = hostfs_iget(ino->i_sb);
50f307401   Al Viro   hostfs_lookup: sw...
578
  	if (IS_ERR(inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	err = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
581
  	name = dentry_name(dentry);
50f307401   Al Viro   hostfs_lookup: sw...
582
583
584
585
586
  	if (name) {
  		err = read_name(inode, name);
  		__putname(name);
  	}
  	if (err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  		iput(inode);
50f307401   Al Viro   hostfs_lookup: sw...
588
  		inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
   out:
50f307401   Al Viro   hostfs_lookup: sw...
591
  	return d_splice_alias(inode, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  }
9e443bc36   James Hogan   um: hostfs: make ...
593
594
  static int hostfs_link(struct dentry *to, struct inode *ino,
  		       struct dentry *from)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
596
597
  	char *from_name, *to_name;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598

c5322220e   Al Viro   hostfs: get rid o...
599
  	if ((from_name = dentry_name(from)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
600
  		return -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
601
  	to_name = dentry_name(to);
84b3db04c   Jeff Dike   uml: fix hostfs s...
602
  	if (to_name == NULL) {
e9193059b   Al Viro   hostfs: fix races...
603
  		__putname(from_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
604
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
606
  	err = link_file(to_name, from_name);
e9193059b   Al Viro   hostfs: fix races...
607
608
  	__putname(from_name);
  	__putname(to_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
609
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  }
9e443bc36   James Hogan   um: hostfs: make ...
611
  static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
615
  	if (append)
f1adc05e7   Jeff Dike   uml: hostfs style...
616
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617

f8d7e1877   Al Viro   leak in hostfs_un...
618
619
  	if ((file = dentry_name(dentry)) == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  	err = unlink_file(file);
e9193059b   Al Viro   hostfs: fix races...
621
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
622
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  }
9e443bc36   James Hogan   um: hostfs: make ...
624
625
  static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
  			  const char *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
629
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
630
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  	err = make_symlink(file, to);
e9193059b   Al Viro   hostfs: fix races...
632
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
633
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
  }
9e443bc36   James Hogan   um: hostfs: make ...
635
  static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
639
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
640
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  	err = do_mkdir(file, mode);
e9193059b   Al Viro   hostfs: fix races...
642
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
643
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  }
9e443bc36   James Hogan   um: hostfs: make ...
645
  static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
649
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
650
  		return -ENOMEM;
6380161ce   Dominik Brodowski   hostfs: rename do...
651
  	err = hostfs_do_rmdir(file);
e9193059b   Al Viro   hostfs: fix races...
652
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
653
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  }
1a67aafb5   Al Viro   switch ->mknod() ...
655
  static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
  {
  	struct inode *inode;
  	char *name;
0a370e5de   David Howells   iget: stop HOSTFS...
659
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660

0a370e5de   David Howells   iget: stop HOSTFS...
661
662
663
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
665
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  	err = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
668
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
669
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
  		goto out_put;
  
  	init_special_inode(inode, mode, dev);
88f6cd0c3   Johannes Stezenbach   [PATCH] uml: fix ...
673
  	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
9f2dfda2f   Vegard Nossum   uml: fix hostfs m...
674
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
  		goto out_free;
  
  	err = read_name(inode, name);
e9193059b   Al Viro   hostfs: fix races...
678
  	__putname(name);
5e2df28cc   Al Viro   hostfs: pass path...
679
680
  	if (err)
  		goto out_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
  
  	d_instantiate(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
683
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
  
   out_free:
e9193059b   Al Viro   hostfs: fix races...
686
  	__putname(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
690
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  }
9a423bb6e   Miklos Szeredi   hostfs: support r...
692
693
694
  static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
  			  struct inode *new_dir, struct dentry *new_dentry,
  			  unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  {
9a423bb6e   Miklos Szeredi   hostfs: support r...
696
  	char *old_name, *new_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	int err;
9a423bb6e   Miklos Szeredi   hostfs: support r...
698
699
700
701
702
  	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
  		return -EINVAL;
  
  	old_name = dentry_name(old_dentry);
  	if (old_name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
703
  		return -ENOMEM;
9a423bb6e   Miklos Szeredi   hostfs: support r...
704
705
706
  	new_name = dentry_name(new_dentry);
  	if (new_name == NULL) {
  		__putname(old_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
707
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
  	}
9a423bb6e   Miklos Szeredi   hostfs: support r...
709
710
711
712
713
714
715
  	if (!flags)
  		err = rename_file(old_name, new_name);
  	else
  		err = rename2_file(old_name, new_name, flags);
  
  	__putname(old_name);
  	__putname(new_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
716
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  }
9e443bc36   James Hogan   um: hostfs: make ...
718
  static int hostfs_permission(struct inode *ino, int desired)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
  {
  	char *name;
  	int r = 0, w = 0, x = 0, err;
10556cb21   Al Viro   ->permission() sa...
722
  	if (desired & MAY_NOT_BLOCK)
b74c79e99   Nick Piggin   fs: provide rcu-w...
723
  		return -ECHILD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
  	if (desired & MAY_READ) r = 1;
  	if (desired & MAY_WRITE) w = 1;
  	if (desired & MAY_EXEC) x = 1;
c5322220e   Al Viro   hostfs: get rid o...
727
  	name = inode_name(ino);
f1adc05e7   Jeff Dike   uml: hostfs style...
728
729
  	if (name == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  
  	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
84b3db04c   Jeff Dike   uml: fix hostfs s...
732
  	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
  		err = 0;
  	else
  		err = access_file(name, r, w, x);
e9193059b   Al Viro   hostfs: fix races...
736
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
737
  	if (!err)
2830ba7f3   Al Viro   ->permission() sa...
738
  		err = generic_permission(ino, desired);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
  	return err;
  }
9e443bc36   James Hogan   um: hostfs: make ...
741
  static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  {
2b0143b5c   David Howells   VFS: normal files...
743
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
  	struct hostfs_iattr attrs;
  	char *name;
  	int err;
1025774ce   Christoph Hellwig   remove inode_setattr
747
  	int fd = HOSTFS_I(inode)->fd;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
748

31051c85b   Jan Kara   fs: Give dentry t...
749
  	err = setattr_prepare(dentry, attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  	if (err)
  		return err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
752
  	if (append)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
  		attr->ia_valid &= ~ATTR_SIZE;
  
  	attrs.ia_valid = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
756
  	if (attr->ia_valid & ATTR_MODE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
  		attrs.ia_valid |= HOSTFS_ATTR_MODE;
  		attrs.ia_mode = attr->ia_mode;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
760
  	if (attr->ia_valid & ATTR_UID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
  		attrs.ia_valid |= HOSTFS_ATTR_UID;
29f82ae56   Eric W. Biederman   userns: Convert h...
762
  		attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
764
  	if (attr->ia_valid & ATTR_GID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  		attrs.ia_valid |= HOSTFS_ATTR_GID;
29f82ae56   Eric W. Biederman   userns: Convert h...
766
  		attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
768
  	if (attr->ia_valid & ATTR_SIZE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
  		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
  		attrs.ia_size = attr->ia_size;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
772
  	if (attr->ia_valid & ATTR_ATIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
95582b008   Deepa Dinamani   vfs: change inode...
774
  		attrs.ia_atime = timespec64_to_timespec(attr->ia_atime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
776
  	if (attr->ia_valid & ATTR_MTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
95582b008   Deepa Dinamani   vfs: change inode...
778
  		attrs.ia_mtime = timespec64_to_timespec(attr->ia_mtime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
780
  	if (attr->ia_valid & ATTR_CTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
95582b008   Deepa Dinamani   vfs: change inode...
782
  		attrs.ia_ctime = timespec64_to_timespec(attr->ia_ctime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
784
  	if (attr->ia_valid & ATTR_ATIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
787
  	if (attr->ia_valid & ATTR_MTIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
  	}
c5322220e   Al Viro   hostfs: get rid o...
790
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
791
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
792
  		return -ENOMEM;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
793
  	err = set_attr(name, &attrs, fd);
e9193059b   Al Viro   hostfs: fix races...
794
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
795
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
796
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797

1025774ce   Christoph Hellwig   remove inode_setattr
798
  	if ((attr->ia_valid & ATTR_SIZE) &&
bc077320f   Marco Stornelli   hostfs: fix a not...
799
  	    attr->ia_size != i_size_read(inode))
3be2be0a3   Marco Stornelli   hostfs: drop vmtr...
800
  		truncate_setsize(inode, attr->ia_size);
1025774ce   Christoph Hellwig   remove inode_setattr
801
802
803
804
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
806
  static const struct inode_operations hostfs_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
810
  static const struct inode_operations hostfs_dir_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
813
814
815
816
817
818
  	.create		= hostfs_create,
  	.lookup		= hostfs_lookup,
  	.link		= hostfs_link,
  	.unlink		= hostfs_unlink,
  	.symlink	= hostfs_symlink,
  	.mkdir		= hostfs_mkdir,
  	.rmdir		= hostfs_rmdir,
  	.mknod		= hostfs_mknod,
2773bf00a   Miklos Szeredi   fs: rename "renam...
819
  	.rename		= hostfs_rename2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  };
6b2553918   Al Viro   replace ->follow_...
823
  static const char *hostfs_get_link(struct dentry *dentry,
fceef393a   Al Viro   switch ->get_link...
824
825
  				   struct inode *inode,
  				   struct delayed_call *done)
d0352d3ed   Al Viro   hostfs: sanitize ...
826
  {
6b2553918   Al Viro   replace ->follow_...
827
828
829
  	char *link;
  	if (!dentry)
  		return ERR_PTR(-ECHILD);
fceef393a   Al Viro   switch ->get_link...
830
  	link = kmalloc(PATH_MAX, GFP_KERNEL);
d0352d3ed   Al Viro   hostfs: sanitize ...
831
832
833
834
  	if (link) {
  		char *path = dentry_name(dentry);
  		int err = -ENOMEM;
  		if (path) {
3b6036d14   Al Viro   hostfs ->follow_l...
835
  			err = hostfs_do_readlink(path, link, PATH_MAX);
d0352d3ed   Al Viro   hostfs: sanitize ...
836
837
  			if (err == PATH_MAX)
  				err = -E2BIG;
e9193059b   Al Viro   hostfs: fix races...
838
  			__putname(path);
d0352d3ed   Al Viro   hostfs: sanitize ...
839
840
  		}
  		if (err < 0) {
fceef393a   Al Viro   switch ->get_link...
841
  			kfree(link);
680baacbc   Al Viro   new ->follow_link...
842
  			return ERR_PTR(err);
d0352d3ed   Al Viro   hostfs: sanitize ...
843
844
  		}
  	} else {
680baacbc   Al Viro   new ->follow_link...
845
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
  	}
d0352d3ed   Al Viro   hostfs: sanitize ...
847

fceef393a   Al Viro   switch ->get_link...
848
849
  	set_delayed_call(done, kfree_link, link);
  	return link;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  }
d0352d3ed   Al Viro   hostfs: sanitize ...
851
  static const struct inode_operations hostfs_link_iops = {
6b2553918   Al Viro   replace ->follow_...
852
  	.get_link	= hostfs_get_link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
  };
  
  static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
  {
  	struct inode *root_inode;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
858
  	char *host_root_path, *req_root = d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
862
863
864
  	int err;
  
  	sb->s_blocksize = 1024;
  	sb->s_blocksize_bits = 10;
  	sb->s_magic = HOSTFS_SUPER_MAGIC;
  	sb->s_op = &hostfs_sbops;
b26d4cd38   Al Viro   consolidate simpl...
865
  	sb->s_d_op = &simple_dentry_operations;
752fa51e4   Wolfgang Illmeyer   hostfs: set maxim...
866
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867

a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
868
  	/* NULL is printed as <NULL> by sprintf: avoid that. */
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
869
870
  	if (req_root == NULL)
  		req_root = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
  
  	err = -ENOMEM;
601d2c38b   Al Viro   hostfs: don't kee...
873
874
  	sb->s_fs_info = host_root_path =
  		kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
875
  	if (host_root_path == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  		goto out;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
877
  	sprintf(host_root_path, "%s/%s", root_ino, req_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878

52b209f7b   Al Viro   get rid of hostfs...
879
880
  	root_inode = new_inode(sb);
  	if (!root_inode)
601d2c38b   Al Viro   hostfs: don't kee...
881
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882

4754b8255   Al Viro   hostfs: get rid o...
883
884
885
  	err = read_name(root_inode, host_root_path);
  	if (err)
  		goto out_put;
52b209f7b   Al Viro   get rid of hostfs...
886

4754b8255   Al Viro   hostfs: get rid o...
887
  	if (S_ISLNK(root_inode->i_mode)) {
52b209f7b   Al Viro   get rid of hostfs...
888
  		char *name = follow_link(host_root_path);
8a545f185   Dan Carpenter   hostfs: Freeing a...
889
  		if (IS_ERR(name)) {
52b209f7b   Al Viro   get rid of hostfs...
890
  			err = PTR_ERR(name);
8a545f185   Dan Carpenter   hostfs: Freeing a...
891
892
893
  			goto out_put;
  		}
  		err = read_name(root_inode, name);
52b209f7b   Al Viro   get rid of hostfs...
894
  		kfree(name);
4754b8255   Al Viro   hostfs: get rid o...
895
896
  		if (err)
  			goto out_put;
52b209f7b   Al Viro   get rid of hostfs...
897
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
  	err = -ENOMEM;
48fde701a   Al Viro   switch open-coded...
900
  	sb->s_root = d_make_root(root_inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
901
  	if (sb->s_root == NULL)
48fde701a   Al Viro   switch open-coded...
902
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903

f1adc05e7   Jeff Dike   uml: hostfs style...
904
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905

f1adc05e7   Jeff Dike   uml: hostfs style...
906
907
  out_put:
  	iput(root_inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
908
909
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  }
3c26ff6e4   Al Viro   convert get_sb_no...
911
  static struct dentry *hostfs_read_sb(struct file_system_type *type,
454e2398b   David Howells   [PATCH] VFS: Perm...
912
  			  int flags, const char *dev_name,
3c26ff6e4   Al Viro   convert get_sb_no...
913
  			  void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  {
3c26ff6e4   Al Viro   convert get_sb_no...
915
  	return mount_nodev(type, flags, data, hostfs_fill_sb_common);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  }
601d2c38b   Al Viro   hostfs: don't kee...
917
918
919
920
921
  static void hostfs_kill_sb(struct super_block *s)
  {
  	kill_anon_super(s);
  	kfree(s->s_fs_info);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
  static struct file_system_type hostfs_type = {
  	.owner 		= THIS_MODULE,
  	.name 		= "hostfs",
3c26ff6e4   Al Viro   convert get_sb_no...
925
  	.mount	 	= hostfs_read_sb,
601d2c38b   Al Viro   hostfs: don't kee...
926
  	.kill_sb	= hostfs_kill_sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
  	.fs_flags 	= 0,
  };
3e64fe5b2   Eric W. Biederman   fs: Limit sys_mou...
929
  MODULE_ALIAS_FS("hostfs");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
  
  static int __init init_hostfs(void)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
933
  	return register_filesystem(&hostfs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
936
937
938
939
940
941
942
943
  }
  
  static void __exit exit_hostfs(void)
  {
  	unregister_filesystem(&hostfs_type);
  }
  
  module_init(init_hostfs)
  module_exit(exit_hostfs)
  MODULE_LICENSE("GPL");