Blame view

fs/hostfs/hostfs_kern.c 20.6 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/module.h>
84b3db04c   Jeff Dike   uml: fix hostfs s...
10
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/statfs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
dd2cc4dff   Miklos Szeredi   mount options: fi...
14
  #include <linux/seq_file.h>
6966a9775   Jiri Kosina   UML: fix hostfs b...
15
  #include <linux/mount.h>
d0352d3ed   Al Viro   hostfs: sanitize ...
16
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include "hostfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include "init.h"
84b3db04c   Jeff Dike   uml: fix hostfs s...
19
  #include "kern.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  
  struct hostfs_inode_info {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  	int fd;
aeb5d7270   Al Viro   [PATCH] introduce...
23
  	fmode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  	struct inode vfs_inode;
  };
  
  static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
29
  	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  }
680b0da9b   Josef Sipek   [PATCH] struct pa...
31
  #define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

fe15ce446   Nick Piggin   fs: change d_dele...
33
  static int hostfs_d_delete(const struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
35
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  }
e16404ed0   Al Viro   constify dentry_o...
37
  static const struct dentry_operations hostfs_dentry_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
  	.d_delete		= hostfs_d_delete,
  };
  
  /* Changed in hostfs_args before the kernel starts running */
a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
42
  static char *root_ino = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  static int append = 0;
  
  #define HOSTFS_SUPER_MAGIC 0x00c0ffee
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
46
47
  static const struct inode_operations hostfs_iops;
  static const struct inode_operations hostfs_dir_iops;
d0352d3ed   Al Viro   hostfs: sanitize ...
48
  static const struct inode_operations hostfs_link_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
  
  #ifndef MODULE
  static int __init hostfs_args(char *options, int *add)
  {
  	char *ptr;
  
  	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
  	if (*options != '\0')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
  		root_ino = options;
  
  	options = ptr;
84b3db04c   Jeff Dike   uml: fix hostfs s...
62
  	while (options) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  		ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
64
  		if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  			*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
66
67
  		if (*options != '\0') {
  			if (!strcmp(options, "append"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
  				append = 1;
  			else printf("hostfs_args - unsupported option - %s
  ",
  				    options);
  		}
  		options = ptr;
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
75
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  }
  
  __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...
98
  static char *__dentry_name(struct dentry *dentry, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  {
ec2447c27   Nick Piggin   hostfs: simplify ...
100
  	char *p = dentry_path_raw(dentry, name, PATH_MAX);
e9193059b   Al Viro   hostfs: fix races...
101
102
  	char *root;
  	size_t len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103

e9193059b   Al Viro   hostfs: fix races...
104
105
106
107
  	root = dentry->d_sb->s_fs_info;
  	len = strlen(root);
  	if (IS_ERR(p)) {
  		__putname(name);
f1adc05e7   Jeff Dike   uml: hostfs style...
108
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  	}
850a496f9   Al Viro   hostfs: dumb (and...
110
  	strlcpy(name, root, PATH_MAX);
e9193059b   Al Viro   hostfs: fix races...
111
112
113
114
115
116
117
118
119
  	if (len > p - name) {
  		__putname(name);
  		return NULL;
  	}
  	if (p > name + len) {
  		char *s = name + len;
  		while ((*s++ = *p++) != '\0')
  			;
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
120
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  }
e9193059b   Al Viro   hostfs: fix races...
122
123
124
125
126
  static char *dentry_name(struct dentry *dentry)
  {
  	char *name = __getname();
  	if (!name)
  		return NULL;
e9193059b   Al Viro   hostfs: fix races...
127
128
  	return __dentry_name(dentry, name); /* will unlock */
  }
c5322220e   Al Viro   hostfs: get rid o...
129
  static char *inode_name(struct inode *ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
  {
  	struct dentry *dentry;
ec2447c27   Nick Piggin   hostfs: simplify ...
132
  	char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

ec2447c27   Nick Piggin   hostfs: simplify ...
134
135
  	dentry = d_find_alias(ino);
  	if (!dentry)
e9193059b   Al Viro   hostfs: fix races...
136
  		return NULL;
ec2447c27   Nick Piggin   hostfs: simplify ...
137
138
139
140
141
142
  
  	name = dentry_name(dentry);
  
  	dput(dentry);
  
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
  static char *follow_link(char *link)
  {
  	int len, n;
  	char *name, *resolved, *end;
  
  	len = 64;
84b3db04c   Jeff Dike   uml: fix hostfs s...
150
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  		n = -ENOMEM;
  		name = kmalloc(len, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
153
  		if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  			goto out;
ea7e743e4   WANG Cong   hostfs: fix a dup...
155
  		n = hostfs_do_readlink(link, name, len);
84b3db04c   Jeff Dike   uml: fix hostfs s...
156
  		if (n < len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
  			break;
  		len *= 2;
  		kfree(name);
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
161
  	if (n < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  		goto out_free;
84b3db04c   Jeff Dike   uml: fix hostfs s...
163
  	if (*name == '/')
f1adc05e7   Jeff Dike   uml: hostfs style...
164
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  
  	end = strrchr(link, '/');
84b3db04c   Jeff Dike   uml: fix hostfs s...
167
  	if (end == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
168
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
  
  	*(end + 1) = '\0';
  	len = strlen(link) + strlen(name) + 1;
  
  	resolved = kmalloc(len, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
174
  	if (resolved == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
  		n = -ENOMEM;
  		goto out_free;
  	}
  
  	sprintf(resolved, "%s%s", link, name);
  	kfree(name);
  	kfree(link);
f1adc05e7   Jeff Dike   uml: hostfs style...
182
  	return resolved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
  
   out_free:
  	kfree(name);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
187
  	return ERR_PTR(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  }
0a370e5de   David Howells   iget: stop HOSTFS...
189
190
  static struct inode *hostfs_iget(struct super_block *sb)
  {
52b209f7b   Al Viro   get rid of hostfs...
191
  	struct inode *inode = new_inode(sb);
0a370e5de   David Howells   iget: stop HOSTFS...
192
193
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
0a370e5de   David Howells   iget: stop HOSTFS...
194
195
  	return inode;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
196
  int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  {
84b3db04c   Jeff Dike   uml: fix hostfs s...
198
199
  	/*
  	 * do_statfs uses struct statfs64 internally, but the linux kernel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
  	 * 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...
209
  	err = do_statfs(dentry->d_sb->s_fs_info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
  			&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...
212
  			&sf->f_namelen);
84b3db04c   Jeff Dike   uml: fix hostfs s...
213
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
214
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
  	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...
221
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
  }
  
  static struct inode *hostfs_alloc_inode(struct super_block *sb)
  {
  	struct hostfs_inode_info *hi;
601d2c38b   Al Viro   hostfs: don't kee...
227
  	hi = kzalloc(sizeof(*hi), GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
228
  	if (hi == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
229
  		return NULL;
601d2c38b   Al Viro   hostfs: don't kee...
230
  	hi->fd = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  	inode_init_once(&hi->vfs_inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
232
  	return &hi->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  }
e971a6d7b   Al Viro   stop icache pollu...
234
  static void hostfs_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  {
fef266580   Mark Fasheh   [PATCH] update fi...
236
  	truncate_inode_pages(&inode->i_data, 0);
e971a6d7b   Al Viro   stop icache pollu...
237
  	end_writeback(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
238
  	if (HOSTFS_I(inode)->fd != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
  		close_file(&HOSTFS_I(inode)->fd);
  		HOSTFS_I(inode)->fd = -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
243
  static void hostfs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
245
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
  	kfree(HOSTFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
248
249
250
251
252
  
  static void hostfs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, hostfs_i_callback);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253

34c80b1d9   Al Viro   vfs: switch ->sho...
254
  static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
dd2cc4dff   Miklos Szeredi   mount options: fi...
255
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
256
  	const char *root_path = root->d_sb->s_fs_info;
dd2cc4dff   Miklos Szeredi   mount options: fi...
257
258
259
260
261
262
263
  	size_t offset = strlen(root_ino) + 1;
  
  	if (strlen(root_path) > offset)
  		seq_printf(seq, ",%s", root_path + offset);
  
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
264
  static const struct super_operations hostfs_sbops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  	.alloc_inode	= hostfs_alloc_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	.destroy_inode	= hostfs_destroy_inode,
e971a6d7b   Al Viro   stop icache pollu...
267
  	.evict_inode	= hostfs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  	.statfs		= hostfs_statfs,
dd2cc4dff   Miklos Szeredi   mount options: fi...
269
  	.show_options	= hostfs_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
  };
  
  int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
  {
  	void *dir;
  	char *name;
  	unsigned long long next, ino;
  	int error, len;
c5322220e   Al Viro   hostfs: get rid o...
278
  	name = dentry_name(file->f_path.dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
279
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
280
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	dir = open_dir(name, &error);
e9193059b   Al Viro   hostfs: fix races...
282
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
283
  	if (dir == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
284
  		return -error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	next = file->f_pos;
84b3db04c   Jeff Dike   uml: fix hostfs s...
286
  	while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  		error = (*filldir)(ent, name, len, file->f_pos,
  				   ino, DT_UNKNOWN);
84b3db04c   Jeff Dike   uml: fix hostfs s...
289
  		if (error) break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
  		file->f_pos = next;
  	}
  	close_dir(dir);
f1adc05e7   Jeff Dike   uml: hostfs style...
293
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
  }
  
  int hostfs_file_open(struct inode *ino, struct file *file)
  {
f8ad850f1   Al Viro   try to get rid of...
298
  	static DEFINE_MUTEX(open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	char *name;
aeb5d7270   Al Viro   [PATCH] introduce...
300
  	fmode_t mode = 0;
f8ad850f1   Al Viro   try to get rid of...
301
  	int err;
aeb5d7270   Al Viro   [PATCH] introduce...
302
  	int r = 0, w = 0, fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
  
  	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
84b3db04c   Jeff Dike   uml: fix hostfs s...
305
  	if ((mode & HOSTFS_I(ino)->mode) == mode)
f1adc05e7   Jeff Dike   uml: hostfs style...
306
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307

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

f8ad850f1   Al Viro   try to get rid of...
310
311
  retry:
  	if (mode & FMODE_READ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  		r = 1;
f8ad850f1   Al Viro   try to get rid of...
313
  	if (mode & FMODE_WRITE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  		w = 1;
84b3db04c   Jeff Dike   uml: fix hostfs s...
315
  	if (w)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  		r = 1;
c5322220e   Al Viro   hostfs: get rid o...
317
  	name = dentry_name(file->f_path.dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
318
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
319
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  
  	fd = open_file(name, r, w, append);
e9193059b   Al Viro   hostfs: fix races...
322
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
323
  	if (fd < 0)
f1adc05e7   Jeff Dike   uml: hostfs style...
324
  		return fd;
f8ad850f1   Al Viro   try to get rid of...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  
  	mutex_lock(&open_mutex);
  	/* somebody else had handled it first? */
  	if ((mode & HOSTFS_I(ino)->mode) == mode) {
  		mutex_unlock(&open_mutex);
  		return 0;
  	}
  	if ((mode | HOSTFS_I(ino)->mode) != mode) {
  		mode |= HOSTFS_I(ino)->mode;
  		mutex_unlock(&open_mutex);
  		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) {
  			mutex_unlock(&open_mutex);
  			return err;
  		}
  	}
  	HOSTFS_I(ino)->mode = mode;
  	mutex_unlock(&open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350

f1adc05e7   Jeff Dike   uml: hostfs style...
351
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
353
  int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  {
02c24a821   Josef Bacik   fs: push i_mutex ...
355
356
357
358
359
360
361
362
363
364
365
366
  	struct inode *inode = file->f_mapping->host;
  	int ret;
  
  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
  	if (ret)
  		return ret;
  
  	mutex_lock(&inode->i_mutex);
  	ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
  	mutex_unlock(&inode->i_mutex);
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
368
  static const struct file_operations hostfs_file_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	.llseek		= generic_file_llseek,
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
370
  	.read		= do_sync_read,
5ffc4ef45   Jens Axboe   sendfile: remove ...
371
  	.splice_read	= generic_file_splice_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  	.aio_read	= generic_file_aio_read,
  	.aio_write	= generic_file_aio_write,
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
374
  	.write		= do_sync_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
  	.mmap		= generic_file_mmap,
  	.open		= hostfs_file_open,
  	.release	= NULL,
  	.fsync		= hostfs_fsync,
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
380
  static const struct file_operations hostfs_dir_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  	.llseek		= generic_file_llseek,
  	.readdir	= hostfs_readdir,
  	.read		= generic_read_dir,
  };
  
  int hostfs_writepage(struct page *page, struct writeback_control *wbc)
  {
  	struct address_space *mapping = page->mapping;
  	struct inode *inode = mapping->host;
  	char *buffer;
  	unsigned long long base;
  	int count = PAGE_CACHE_SIZE;
  	int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
  	int err;
  
  	if (page->index >= end_index)
  		count = inode->i_size & (PAGE_CACHE_SIZE-1);
  
  	buffer = kmap(page);
  	base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
  
  	err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
84b3db04c   Jeff Dike   uml: fix hostfs s...
403
  	if (err != count) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  		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;
  }
  
  int hostfs_readpage(struct file *file, struct page *page)
  {
  	char *buffer;
  	long long start;
  	int err = 0;
  
  	start = (long long) page->index << PAGE_CACHE_SHIFT;
  	buffer = kmap(page);
  	err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
  			PAGE_CACHE_SIZE);
84b3db04c   Jeff Dike   uml: fix hostfs s...
432
433
  	if (err < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
440
441
442
443
  
  	memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
  
  	flush_dcache_page(page);
  	SetPageUptodate(page);
  	if (PageError(page)) ClearPageError(page);
  	err = 0;
   out:
  	kunmap(page);
  	unlock_page(page);
f1adc05e7   Jeff Dike   uml: hostfs style...
444
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  }
ae361ff46   Nick Piggin   hostfs: convert t...
446
447
448
  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
449
  {
ae361ff46   Nick Piggin   hostfs: convert t...
450
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451

54566b2c1   Nick Piggin   fs: symlink write...
452
  	*pagep = grab_cache_page_write_begin(mapping, index, flags);
ae361ff46   Nick Piggin   hostfs: convert t...
453
454
455
  	if (!*pagep)
  		return -ENOMEM;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  }
ae361ff46   Nick Piggin   hostfs: convert t...
457
458
459
  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
460
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  	struct inode *inode = mapping->host;
ae361ff46   Nick Piggin   hostfs: convert t...
462
463
464
  	void *buffer;
  	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465

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

ae361ff46   Nick Piggin   hostfs: convert t...
470
471
  	if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
  		SetPageUptodate(page);
30f04a4ef   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
472

84b3db04c   Jeff Dike   uml: fix hostfs s...
473
474
  	/*
  	 * If err > 0, write_file has added err to pos, so we are comparing
ae361ff46   Nick Piggin   hostfs: convert t...
475
476
477
478
479
480
  	 * i_size against the last byte written.
  	 */
  	if (err > 0 && (pos > inode->i_size))
  		inode->i_size = pos;
  	unlock_page(page);
  	page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481

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

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

4754b8255   Al Viro   hostfs: get rid o...
502
503
  	switch (st.mode & S_IFMT) {
  	case S_IFLNK:
d0352d3ed   Al Viro   hostfs: sanitize ...
504
  		ino->i_op = &hostfs_link_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  		break;
4754b8255   Al Viro   hostfs: get rid o...
506
507
508
  	case S_IFDIR:
  		ino->i_op = &hostfs_dir_iops;
  		ino->i_fop = &hostfs_dir_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  		break;
4754b8255   Al Viro   hostfs: get rid o...
510
511
512
513
514
515
  	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
516
  		break;
4754b8255   Al Viro   hostfs: get rid o...
517
518
519
520
521
  
  	default:
  		ino->i_op = &hostfs_iops;
  		ino->i_fop = &hostfs_file_fops;
  		ino->i_mapping->a_ops = &hostfs_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	}
4754b8255   Al Viro   hostfs: get rid o...
523
524
525
  
  	ino->i_ino = st.ino;
  	ino->i_mode = st.mode;
bfe868486   Miklos Szeredi   filesystems: add ...
526
  	set_nlink(ino, st.nlink);
4754b8255   Al Viro   hostfs: get rid o...
527
528
529
530
531
532
533
534
  	ino->i_uid = st.uid;
  	ino->i_gid = st.gid;
  	ino->i_atime = st.atime;
  	ino->i_mtime = st.mtime;
  	ino->i_ctime = st.ctime;
  	ino->i_size = st.size;
  	ino->i_blocks = st.blocks;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  }
4acdaf27e   Al Viro   switch ->create()...
536
  int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
84b3db04c   Jeff Dike   uml: fix hostfs s...
537
  		  struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
  {
  	struct inode *inode;
  	char *name;
  	int error, fd;
0a370e5de   David Howells   iget: stop HOSTFS...
542
543
544
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
545
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
546
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  	error = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
549
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
550
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
555
556
  		goto out_put;
  
  	fd = file_create(name,
  			 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
  			 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
  			 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
4754b8255   Al Viro   hostfs: get rid o...
557
  	if (fd < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		error = fd;
4754b8255   Al Viro   hostfs: get rid o...
559
  	else
5e2df28cc   Al Viro   hostfs: pass path...
560
  		error = read_name(inode, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561

e9193059b   Al Viro   hostfs: fix races...
562
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
563
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
568
  		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...
569
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
574
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
  }
  
  struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
f1adc05e7   Jeff Dike   uml: hostfs style...
578
  			     struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
582
  {
  	struct inode *inode;
  	char *name;
  	int err;
0a370e5de   David Howells   iget: stop HOSTFS...
583
584
585
  	inode = hostfs_iget(ino->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
587
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  	err = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
590
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
591
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
  		goto out_put;
  
  	err = read_name(inode, name);
5e2df28cc   Al Viro   hostfs: pass path...
595

e9193059b   Al Viro   hostfs: fix races...
596
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
597
  	if (err == -ENOENT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
  		iput(inode);
  		inode = NULL;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
601
  	else if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  		goto out_put;
  
  	d_add(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
605
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
610
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
  int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
614
615
  	char *from_name, *to_name;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616

c5322220e   Al Viro   hostfs: get rid o...
617
  	if ((from_name = dentry_name(from)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
618
  		return -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
619
  	to_name = dentry_name(to);
84b3db04c   Jeff Dike   uml: fix hostfs s...
620
  	if (to_name == NULL) {
e9193059b   Al Viro   hostfs: fix races...
621
  		__putname(from_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
622
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
624
  	err = link_file(to_name, from_name);
e9193059b   Al Viro   hostfs: fix races...
625
626
  	__putname(from_name);
  	__putname(to_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
627
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
632
633
  }
  
  int hostfs_unlink(struct inode *ino, struct dentry *dentry)
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
634
  	if (append)
f1adc05e7   Jeff Dike   uml: hostfs style...
635
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

f8d7e1877   Al Viro   leak in hostfs_un...
637
638
  	if ((file = dentry_name(dentry)) == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  	err = unlink_file(file);
e9193059b   Al Viro   hostfs: fix races...
640
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
641
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
646
647
  }
  
  int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
648
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
649
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	err = make_symlink(file, to);
e9193059b   Al Viro   hostfs: fix races...
651
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
652
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
654
  int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
658
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
659
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  	err = do_mkdir(file, mode);
e9193059b   Al Viro   hostfs: fix races...
661
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
662
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
667
668
  }
  
  int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
669
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
670
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	err = do_rmdir(file);
e9193059b   Al Viro   hostfs: fix races...
672
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
673
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  }
1a67aafb5   Al Viro   switch ->mknod() ...
675
  static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
  {
  	struct inode *inode;
  	char *name;
0a370e5de   David Howells   iget: stop HOSTFS...
679
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680

0a370e5de   David Howells   iget: stop HOSTFS...
681
682
683
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
685
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  	err = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
688
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
689
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
  		goto out_put;
  
  	init_special_inode(inode, mode, dev);
88f6cd0c3   Johannes Stezenbach   [PATCH] uml: fix ...
693
  	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
e9193059b   Al Viro   hostfs: fix races...
694
  	if (!err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
  		goto out_free;
  
  	err = read_name(inode, name);
e9193059b   Al Viro   hostfs: fix races...
698
  	__putname(name);
5e2df28cc   Al Viro   hostfs: pass path...
699
700
  	if (err)
  		goto out_put;
84b3db04c   Jeff Dike   uml: fix hostfs s...
701
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
  		goto out_put;
  
  	d_instantiate(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
705
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  
   out_free:
e9193059b   Al Viro   hostfs: fix races...
708
  	__putname(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
712
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
718
719
  }
  
  int hostfs_rename(struct inode *from_ino, struct dentry *from,
  		  struct inode *to_ino, struct dentry *to)
  {
  	char *from_name, *to_name;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
720
  	if ((from_name = dentry_name(from)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
721
  		return -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
722
  	if ((to_name = dentry_name(to)) == NULL) {
e9193059b   Al Viro   hostfs: fix races...
723
  		__putname(from_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
724
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
  	}
  	err = rename_file(from_name, to_name);
e9193059b   Al Viro   hostfs: fix races...
727
728
  	__putname(from_name);
  	__putname(to_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
729
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  }
10556cb21   Al Viro   ->permission() sa...
731
  int hostfs_permission(struct inode *ino, int desired)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
  {
  	char *name;
  	int r = 0, w = 0, x = 0, err;
10556cb21   Al Viro   ->permission() sa...
735
  	if (desired & MAY_NOT_BLOCK)
b74c79e99   Nick Piggin   fs: provide rcu-w...
736
  		return -ECHILD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
  	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...
740
  	name = inode_name(ino);
f1adc05e7   Jeff Dike   uml: hostfs style...
741
742
  	if (name == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
  
  	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
84b3db04c   Jeff Dike   uml: fix hostfs s...
745
  	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
  		err = 0;
  	else
  		err = access_file(name, r, w, x);
e9193059b   Al Viro   hostfs: fix races...
749
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
750
  	if (!err)
2830ba7f3   Al Viro   ->permission() sa...
751
  		err = generic_permission(ino, desired);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
  	return err;
  }
  
  int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
  {
1025774ce   Christoph Hellwig   remove inode_setattr
757
  	struct inode *inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
  	struct hostfs_iattr attrs;
  	char *name;
  	int err;
1025774ce   Christoph Hellwig   remove inode_setattr
761
  	int fd = HOSTFS_I(inode)->fd;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
762

1025774ce   Christoph Hellwig   remove inode_setattr
763
  	err = inode_change_ok(inode, attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
  	if (err)
  		return err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
766
  	if (append)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
  		attr->ia_valid &= ~ATTR_SIZE;
  
  	attrs.ia_valid = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
770
  	if (attr->ia_valid & ATTR_MODE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
  		attrs.ia_valid |= HOSTFS_ATTR_MODE;
  		attrs.ia_mode = attr->ia_mode;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
774
  	if (attr->ia_valid & ATTR_UID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
  		attrs.ia_valid |= HOSTFS_ATTR_UID;
  		attrs.ia_uid = attr->ia_uid;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
778
  	if (attr->ia_valid & ATTR_GID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
  		attrs.ia_valid |= HOSTFS_ATTR_GID;
  		attrs.ia_gid = attr->ia_gid;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
782
  	if (attr->ia_valid & ATTR_SIZE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
  		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
  		attrs.ia_size = attr->ia_size;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
786
  	if (attr->ia_valid & ATTR_ATIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
  		attrs.ia_atime = attr->ia_atime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
790
  	if (attr->ia_valid & ATTR_MTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
  		attrs.ia_mtime = attr->ia_mtime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
794
  	if (attr->ia_valid & ATTR_CTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
  		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
  		attrs.ia_ctime = attr->ia_ctime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
798
  	if (attr->ia_valid & ATTR_ATIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
801
  	if (attr->ia_valid & ATTR_MTIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
  	}
c5322220e   Al Viro   hostfs: get rid o...
804
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
805
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
806
  		return -ENOMEM;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
807
  	err = set_attr(name, &attrs, fd);
e9193059b   Al Viro   hostfs: fix races...
808
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
809
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
810
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811

1025774ce   Christoph Hellwig   remove inode_setattr
812
813
814
815
816
817
818
819
820
821
822
823
  	if ((attr->ia_valid & ATTR_SIZE) &&
  	    attr->ia_size != i_size_read(inode)) {
  		int error;
  
  		error = vmtruncate(inode, attr->ia_size);
  		if (err)
  			return err;
  	}
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
825
  static const struct inode_operations hostfs_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
828
829
830
831
832
833
  	.create		= hostfs_create,
  	.link		= hostfs_link,
  	.unlink		= hostfs_unlink,
  	.symlink	= hostfs_symlink,
  	.mkdir		= hostfs_mkdir,
  	.rmdir		= hostfs_rmdir,
  	.mknod		= hostfs_mknod,
  	.rename		= hostfs_rename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
837
  static const struct inode_operations hostfs_dir_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
840
841
842
843
844
845
846
  	.create		= hostfs_create,
  	.lookup		= hostfs_lookup,
  	.link		= hostfs_link,
  	.unlink		= hostfs_unlink,
  	.symlink	= hostfs_symlink,
  	.mkdir		= hostfs_mkdir,
  	.rmdir		= hostfs_rmdir,
  	.mknod		= hostfs_mknod,
  	.rename		= hostfs_rename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  };
d0352d3ed   Al Viro   hostfs: sanitize ...
850
851
852
853
854
855
856
  static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
  {
  	char *link = __getname();
  	if (link) {
  		char *path = dentry_name(dentry);
  		int err = -ENOMEM;
  		if (path) {
3b6036d14   Al Viro   hostfs ->follow_l...
857
  			err = hostfs_do_readlink(path, link, PATH_MAX);
d0352d3ed   Al Viro   hostfs: sanitize ...
858
859
  			if (err == PATH_MAX)
  				err = -E2BIG;
e9193059b   Al Viro   hostfs: fix races...
860
  			__putname(path);
d0352d3ed   Al Viro   hostfs: sanitize ...
861
862
863
864
865
866
867
  		}
  		if (err < 0) {
  			__putname(link);
  			link = ERR_PTR(err);
  		}
  	} else {
  		link = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	}
d0352d3ed   Al Viro   hostfs: sanitize ...
869
870
871
872
873
874
875
876
877
878
  
  	nd_set_link(nd, link);
  	return NULL;
  }
  
  static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
  {
  	char *s = nd_get_link(nd);
  	if (!IS_ERR(s))
  		__putname(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  }
d0352d3ed   Al Viro   hostfs: sanitize ...
880
881
882
883
  static const struct inode_operations hostfs_link_iops = {
  	.readlink	= generic_readlink,
  	.follow_link	= hostfs_follow_link,
  	.put_link	= hostfs_put_link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
  };
  
  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...
889
  	char *host_root_path, *req_root = d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
893
894
895
  	int err;
  
  	sb->s_blocksize = 1024;
  	sb->s_blocksize_bits = 10;
  	sb->s_magic = HOSTFS_SUPER_MAGIC;
  	sb->s_op = &hostfs_sbops;
f772c4a6a   Al Viro   switch hostfs
896
  	sb->s_d_op = &hostfs_dentry_ops;
752fa51e4   Wolfgang Illmeyer   hostfs: set maxim...
897
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898

a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
899
  	/* NULL is printed as <NULL> by sprintf: avoid that. */
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
900
901
  	if (req_root == NULL)
  		req_root = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
  
  	err = -ENOMEM;
601d2c38b   Al Viro   hostfs: don't kee...
904
905
  	sb->s_fs_info = host_root_path =
  		kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
906
  	if (host_root_path == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  		goto out;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
908
  	sprintf(host_root_path, "%s/%s", root_ino, req_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909

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

4754b8255   Al Viro   hostfs: get rid o...
914
915
916
  	err = read_name(root_inode, host_root_path);
  	if (err)
  		goto out_put;
52b209f7b   Al Viro   get rid of hostfs...
917

4754b8255   Al Viro   hostfs: get rid o...
918
  	if (S_ISLNK(root_inode->i_mode)) {
52b209f7b   Al Viro   get rid of hostfs...
919
920
921
922
923
924
  		char *name = follow_link(host_root_path);
  		if (IS_ERR(name))
  			err = PTR_ERR(name);
  		else
  			err = read_name(root_inode, name);
  		kfree(name);
4754b8255   Al Viro   hostfs: get rid o...
925
926
  		if (err)
  			goto out_put;
52b209f7b   Al Viro   get rid of hostfs...
927
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
  	err = -ENOMEM;
  	sb->s_root = d_alloc_root(root_inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
931
  	if (sb->s_root == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  		goto out_put;
f1adc05e7   Jeff Dike   uml: hostfs style...
933
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934

f1adc05e7   Jeff Dike   uml: hostfs style...
935
936
  out_put:
  	iput(root_inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
937
938
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  }
3c26ff6e4   Al Viro   convert get_sb_no...
940
  static struct dentry *hostfs_read_sb(struct file_system_type *type,
454e2398b   David Howells   [PATCH] VFS: Perm...
941
  			  int flags, const char *dev_name,
3c26ff6e4   Al Viro   convert get_sb_no...
942
  			  void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
  {
3c26ff6e4   Al Viro   convert get_sb_no...
944
  	return mount_nodev(type, flags, data, hostfs_fill_sb_common);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  }
601d2c38b   Al Viro   hostfs: don't kee...
946
947
948
949
950
  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
951
952
953
  static struct file_system_type hostfs_type = {
  	.owner 		= THIS_MODULE,
  	.name 		= "hostfs",
3c26ff6e4   Al Viro   convert get_sb_no...
954
  	.mount	 	= hostfs_read_sb,
601d2c38b   Al Viro   hostfs: don't kee...
955
  	.kill_sb	= hostfs_kill_sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
958
959
960
  	.fs_flags 	= 0,
  };
  
  static int __init init_hostfs(void)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
961
  	return register_filesystem(&hostfs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
965
966
967
968
969
970
971
  }
  
  static void __exit exit_hostfs(void)
  {
  	unregister_filesystem(&hostfs_type);
  }
  
  module_init(init_hostfs)
  module_exit(exit_hostfs)
  MODULE_LICENSE("GPL");