hostfs_kern.c 20.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10
 * Licensed under the GPL
 *
 * Ported the filesystem routines to 2.5.
 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
 */

#include <linux/fs.h>
#include <linux/module.h>
J
Jeff Dike 已提交
11
#include <linux/mm.h>
L
Linus Torvalds 已提交
12 13
#include <linux/pagemap.h>
#include <linux/statfs.h>
14
#include <linux/slab.h>
M
Miklos Szeredi 已提交
15
#include <linux/seq_file.h>
J
Jiri Kosina 已提交
16
#include <linux/mount.h>
A
Al Viro 已提交
17
#include <linux/namei.h>
L
Linus Torvalds 已提交
18 19
#include "hostfs.h"
#include "init.h"
J
Jeff Dike 已提交
20
#include "kern.h"
L
Linus Torvalds 已提交
21 22 23

struct hostfs_inode_info {
	int fd;
24
	fmode_t mode;
L
Linus Torvalds 已提交
25 26 27 28 29
	struct inode vfs_inode;
};

static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
{
J
Jeff Dike 已提交
30
	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
L
Linus Torvalds 已提交
31 32
}

J
Josef Sipek 已提交
33
#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
L
Linus Torvalds 已提交
34

N
Nick Piggin 已提交
35
static int hostfs_d_delete(const struct dentry *dentry)
L
Linus Torvalds 已提交
36
{
J
Jeff Dike 已提交
37
	return 1;
L
Linus Torvalds 已提交
38 39
}

40
static const struct dentry_operations hostfs_dentry_ops = {
L
Linus Torvalds 已提交
41 42 43 44
	.d_delete		= hostfs_d_delete,
};

/* Changed in hostfs_args before the kernel starts running */
45
static char *root_ino = "";
L
Linus Torvalds 已提交
46 47 48 49
static int append = 0;

#define HOSTFS_SUPER_MAGIC 0x00c0ffee

50 51
static const struct inode_operations hostfs_iops;
static const struct inode_operations hostfs_dir_iops;
A
Al Viro 已提交
52
static const struct inode_operations hostfs_link_iops;
L
Linus Torvalds 已提交
53 54 55 56 57 58 59

#ifndef MODULE
static int __init hostfs_args(char *options, int *add)
{
	char *ptr;

	ptr = strchr(options, ',');
J
Jeff Dike 已提交
60
	if (ptr != NULL)
L
Linus Torvalds 已提交
61
		*ptr++ = '\0';
J
Jeff Dike 已提交
62
	if (*options != '\0')
L
Linus Torvalds 已提交
63 64 65
		root_ino = options;

	options = ptr;
J
Jeff Dike 已提交
66
	while (options) {
L
Linus Torvalds 已提交
67
		ptr = strchr(options, ',');
J
Jeff Dike 已提交
68
		if (ptr != NULL)
L
Linus Torvalds 已提交
69
			*ptr++ = '\0';
J
Jeff Dike 已提交
70 71
		if (*options != '\0') {
			if (!strcmp(options, "append"))
L
Linus Torvalds 已提交
72 73 74 75 76 77
				append = 1;
			else printf("hostfs_args - unsupported option - %s\n",
				    options);
		}
		options = ptr;
	}
J
Jeff Dike 已提交
78
	return 0;
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92
}

__uml_setup("hostfs=", hostfs_args,
"hostfs=<root dir>,<flags>,...\n"
"    This is used to set hostfs parameters.  The root directory argument\n"
"    is used to confine all hostfs mounts to within the specified directory\n"
"    tree on the host.  If this isn't specified, then a user inside UML can\n"
"    mount anything on the host that's accessible to the user that's running\n"
"    it.\n"
"    The only flag currently supported is 'append', which specifies that all\n"
"    files opened by hostfs will be opened in append mode.\n\n"
);
#endif

93
static char *__dentry_name(struct dentry *dentry, char *name)
L
Linus Torvalds 已提交
94
{
N
Nick Piggin 已提交
95
	char *p = dentry_path_raw(dentry, name, PATH_MAX);
96 97
	char *root;
	size_t len;
L
Linus Torvalds 已提交
98

99 100 101 102
	root = dentry->d_sb->s_fs_info;
	len = strlen(root);
	if (IS_ERR(p)) {
		__putname(name);
J
Jeff Dike 已提交
103
		return NULL;
L
Linus Torvalds 已提交
104
	}
105
	strlcpy(name, root, PATH_MAX);
106 107 108 109 110 111 112 113 114
	if (len > p - name) {
		__putname(name);
		return NULL;
	}
	if (p > name + len) {
		char *s = name + len;
		while ((*s++ = *p++) != '\0')
			;
	}
J
Jeff Dike 已提交
115
	return name;
L
Linus Torvalds 已提交
116 117
}

118 119 120 121 122 123 124 125 126
static char *dentry_name(struct dentry *dentry)
{
	char *name = __getname();
	if (!name)
		return NULL;

	return __dentry_name(dentry, name); /* will unlock */
}

A
Al Viro 已提交
127
static char *inode_name(struct inode *ino)
L
Linus Torvalds 已提交
128 129
{
	struct dentry *dentry;
N
Nick Piggin 已提交
130
	char *name;
L
Linus Torvalds 已提交
131

N
Nick Piggin 已提交
132 133
	dentry = d_find_alias(ino);
	if (!dentry)
134
		return NULL;
N
Nick Piggin 已提交
135 136 137 138 139 140

	name = dentry_name(dentry);

	dput(dentry);

	return name;
L
Linus Torvalds 已提交
141 142 143 144 145 146 147 148
}

static char *follow_link(char *link)
{
	int len, n;
	char *name, *resolved, *end;

	len = 64;
J
Jeff Dike 已提交
149
	while (1) {
L
Linus Torvalds 已提交
150 151
		n = -ENOMEM;
		name = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
152
		if (name == NULL)
L
Linus Torvalds 已提交
153 154
			goto out;

155
		n = hostfs_do_readlink(link, name, len);
J
Jeff Dike 已提交
156
		if (n < len)
L
Linus Torvalds 已提交
157 158 159 160
			break;
		len *= 2;
		kfree(name);
	}
J
Jeff Dike 已提交
161
	if (n < 0)
L
Linus Torvalds 已提交
162 163
		goto out_free;

J
Jeff Dike 已提交
164
	if (*name == '/')
J
Jeff Dike 已提交
165
		return name;
L
Linus Torvalds 已提交
166 167

	end = strrchr(link, '/');
J
Jeff Dike 已提交
168
	if (end == NULL)
J
Jeff Dike 已提交
169
		return name;
L
Linus Torvalds 已提交
170 171 172 173 174

	*(end + 1) = '\0';
	len = strlen(link) + strlen(name) + 1;

	resolved = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
175
	if (resolved == NULL) {
L
Linus Torvalds 已提交
176 177 178 179 180 181 182
		n = -ENOMEM;
		goto out_free;
	}

	sprintf(resolved, "%s%s", link, name);
	kfree(name);
	kfree(link);
J
Jeff Dike 已提交
183
	return resolved;
L
Linus Torvalds 已提交
184 185 186 187

 out_free:
	kfree(name);
 out:
J
Jeff Dike 已提交
188
	return ERR_PTR(n);
L
Linus Torvalds 已提交
189 190
}

191 192
static struct inode *hostfs_iget(struct super_block *sb)
{
A
Al Viro 已提交
193
	struct inode *inode = new_inode(sb);
194 195 196 197 198
	if (!inode)
		return ERR_PTR(-ENOMEM);
	return inode;
}

199
int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
L
Linus Torvalds 已提交
200
{
J
Jeff Dike 已提交
201 202
	/*
	 * do_statfs uses struct statfs64 internally, but the linux kernel
L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210 211 212
	 * 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;

213
	err = do_statfs(dentry->d_sb->s_fs_info,
L
Linus Torvalds 已提交
214 215
			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
216
			&sf->f_namelen);
J
Jeff Dike 已提交
217
	if (err)
J
Jeff Dike 已提交
218
		return err;
L
Linus Torvalds 已提交
219 220 221 222 223 224
	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;
J
Jeff Dike 已提交
225
	return 0;
L
Linus Torvalds 已提交
226 227 228 229 230 231
}

static struct inode *hostfs_alloc_inode(struct super_block *sb)
{
	struct hostfs_inode_info *hi;

232
	hi = kzalloc(sizeof(*hi), GFP_KERNEL);
J
Jeff Dike 已提交
233
	if (hi == NULL)
J
Jeff Dike 已提交
234
		return NULL;
235
	hi->fd = -1;
L
Linus Torvalds 已提交
236
	inode_init_once(&hi->vfs_inode);
J
Jeff Dike 已提交
237
	return &hi->vfs_inode;
L
Linus Torvalds 已提交
238 239
}

240
static void hostfs_evict_inode(struct inode *inode)
L
Linus Torvalds 已提交
241
{
242
	truncate_inode_pages(&inode->i_data, 0);
243
	end_writeback(inode);
J
Jeff Dike 已提交
244
	if (HOSTFS_I(inode)->fd != -1) {
L
Linus Torvalds 已提交
245 246 247 248 249
		close_file(&HOSTFS_I(inode)->fd);
		HOSTFS_I(inode)->fd = -1;
	}
}

N
Nick Piggin 已提交
250
static void hostfs_i_callback(struct rcu_head *head)
L
Linus Torvalds 已提交
251
{
N
Nick Piggin 已提交
252
	struct inode *inode = container_of(head, struct inode, i_rcu);
L
Linus Torvalds 已提交
253 254
	kfree(HOSTFS_I(inode));
}
N
Nick Piggin 已提交
255 256 257 258 259

static void hostfs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, hostfs_i_callback);
}
L
Linus Torvalds 已提交
260

261
static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
M
Miklos Szeredi 已提交
262
{
263
	const char *root_path = root->d_sb->s_fs_info;
M
Miklos Szeredi 已提交
264 265 266 267 268 269 270 271
	size_t offset = strlen(root_ino) + 1;

	if (strlen(root_path) > offset)
		seq_printf(seq, ",%s", root_path + offset);

	return 0;
}

272
static const struct super_operations hostfs_sbops = {
L
Linus Torvalds 已提交
273 274
	.alloc_inode	= hostfs_alloc_inode,
	.destroy_inode	= hostfs_destroy_inode,
275
	.evict_inode	= hostfs_evict_inode,
L
Linus Torvalds 已提交
276
	.statfs		= hostfs_statfs,
M
Miklos Szeredi 已提交
277
	.show_options	= hostfs_show_options,
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285 286
};

int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
{
	void *dir;
	char *name;
	unsigned long long next, ino;
	int error, len;

A
Al Viro 已提交
287
	name = dentry_name(file->f_path.dentry);
J
Jeff Dike 已提交
288
	if (name == NULL)
J
Jeff Dike 已提交
289
		return -ENOMEM;
L
Linus Torvalds 已提交
290
	dir = open_dir(name, &error);
291
	__putname(name);
J
Jeff Dike 已提交
292
	if (dir == NULL)
J
Jeff Dike 已提交
293
		return -error;
L
Linus Torvalds 已提交
294
	next = file->f_pos;
J
Jeff Dike 已提交
295
	while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
L
Linus Torvalds 已提交
296 297
		error = (*filldir)(ent, name, len, file->f_pos,
				   ino, DT_UNKNOWN);
J
Jeff Dike 已提交
298
		if (error) break;
L
Linus Torvalds 已提交
299 300 301
		file->f_pos = next;
	}
	close_dir(dir);
J
Jeff Dike 已提交
302
	return 0;
L
Linus Torvalds 已提交
303 304 305 306
}

int hostfs_file_open(struct inode *ino, struct file *file)
{
307
	static DEFINE_MUTEX(open_mutex);
L
Linus Torvalds 已提交
308
	char *name;
309
	fmode_t mode = 0;
310
	int err;
311
	int r = 0, w = 0, fd;
L
Linus Torvalds 已提交
312 313

	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
J
Jeff Dike 已提交
314
	if ((mode & HOSTFS_I(ino)->mode) == mode)
J
Jeff Dike 已提交
315
		return 0;
L
Linus Torvalds 已提交
316

317
	mode |= HOSTFS_I(ino)->mode;
L
Linus Torvalds 已提交
318

319 320
retry:
	if (mode & FMODE_READ)
L
Linus Torvalds 已提交
321
		r = 1;
322
	if (mode & FMODE_WRITE)
L
Linus Torvalds 已提交
323
		w = 1;
J
Jeff Dike 已提交
324
	if (w)
L
Linus Torvalds 已提交
325 326
		r = 1;

A
Al Viro 已提交
327
	name = dentry_name(file->f_path.dentry);
J
Jeff Dike 已提交
328
	if (name == NULL)
J
Jeff Dike 已提交
329
		return -ENOMEM;
L
Linus Torvalds 已提交
330 331

	fd = open_file(name, r, w, append);
332
	__putname(name);
J
Jeff Dike 已提交
333
	if (fd < 0)
J
Jeff Dike 已提交
334
		return fd;
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359

	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);
L
Linus Torvalds 已提交
360

J
Jeff Dike 已提交
361
	return 0;
L
Linus Torvalds 已提交
362 363
}

364
int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
L
Linus Torvalds 已提交
365
{
366 367 368 369 370 371 372 373 374 375 376 377
	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;
L
Linus Torvalds 已提交
378 379
}

380
static const struct file_operations hostfs_file_fops = {
L
Linus Torvalds 已提交
381
	.llseek		= generic_file_llseek,
382
	.read		= do_sync_read,
383
	.splice_read	= generic_file_splice_read,
L
Linus Torvalds 已提交
384 385
	.aio_read	= generic_file_aio_read,
	.aio_write	= generic_file_aio_write,
386
	.write		= do_sync_write,
L
Linus Torvalds 已提交
387 388 389 390 391 392
	.mmap		= generic_file_mmap,
	.open		= hostfs_file_open,
	.release	= NULL,
	.fsync		= hostfs_fsync,
};

393
static const struct file_operations hostfs_dir_fops = {
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
	.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);
J
Jeff Dike 已提交
416
	if (err != count) {
L
Linus Torvalds 已提交
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
		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);
J
Jeff Dike 已提交
445 446
	if (err < 0)
		goto out;
L
Linus Torvalds 已提交
447 448 449 450 451 452 453 454 455 456

	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);
J
Jeff Dike 已提交
457
	return err;
L
Linus Torvalds 已提交
458 459
}

N
Nick Piggin 已提交
460 461 462
int hostfs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
L
Linus Torvalds 已提交
463
{
N
Nick Piggin 已提交
464
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
L
Linus Torvalds 已提交
465

466
	*pagep = grab_cache_page_write_begin(mapping, index, flags);
N
Nick Piggin 已提交
467 468 469
	if (!*pagep)
		return -ENOMEM;
	return 0;
L
Linus Torvalds 已提交
470 471
}

N
Nick Piggin 已提交
472 473 474
int hostfs_write_end(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *page, void *fsdata)
L
Linus Torvalds 已提交
475 476
{
	struct inode *inode = mapping->host;
N
Nick Piggin 已提交
477 478 479
	void *buffer;
	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
	int err;
L
Linus Torvalds 已提交
480 481

	buffer = kmap(page);
N
Nick Piggin 已提交
482 483
	err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
	kunmap(page);
484

N
Nick Piggin 已提交
485 486
	if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
		SetPageUptodate(page);
487

J
Jeff Dike 已提交
488 489
	/*
	 * If err > 0, write_file has added err to pos, so we are comparing
N
Nick Piggin 已提交
490 491 492 493 494 495
	 * 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);
L
Linus Torvalds 已提交
496

J
Jeff Dike 已提交
497
	return err;
L
Linus Torvalds 已提交
498 499
}

500
static const struct address_space_operations hostfs_aops = {
L
Linus Torvalds 已提交
501 502
	.writepage 	= hostfs_writepage,
	.readpage	= hostfs_readpage,
503
	.set_page_dirty = __set_page_dirty_nobuffers,
N
Nick Piggin 已提交
504 505
	.write_begin	= hostfs_write_begin,
	.write_end	= hostfs_write_end,
L
Linus Torvalds 已提交
506 507
};

508
static int read_name(struct inode *ino, char *name)
L
Linus Torvalds 已提交
509
{
510 511 512 513 514
	dev_t rdev;
	struct hostfs_stat st;
	int err = stat_file(name, &st, -1);
	if (err)
		return err;
L
Linus Torvalds 已提交
515

A
Al Viro 已提交
516
	/* Reencode maj and min with the kernel encoding.*/
517
	rdev = MKDEV(st.maj, st.min);
L
Linus Torvalds 已提交
518

519 520
	switch (st.mode & S_IFMT) {
	case S_IFLNK:
A
Al Viro 已提交
521
		ino->i_op = &hostfs_link_iops;
L
Linus Torvalds 已提交
522
		break;
523 524 525
	case S_IFDIR:
		ino->i_op = &hostfs_dir_iops;
		ino->i_fop = &hostfs_dir_fops;
L
Linus Torvalds 已提交
526
		break;
527 528 529 530 531 532
	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;
L
Linus Torvalds 已提交
533
		break;
534 535 536 537 538

	default:
		ino->i_op = &hostfs_iops;
		ino->i_fop = &hostfs_file_fops;
		ino->i_mapping->a_ops = &hostfs_aops;
L
Linus Torvalds 已提交
539
	}
540 541 542

	ino->i_ino = st.ino;
	ino->i_mode = st.mode;
M
Miklos Szeredi 已提交
543
	set_nlink(ino, st.nlink);
544 545 546 547 548 549 550 551
	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;
L
Linus Torvalds 已提交
552 553
}

A
Al Viro 已提交
554
int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
J
Jeff Dike 已提交
555
		  struct nameidata *nd)
L
Linus Torvalds 已提交
556 557 558 559 560
{
	struct inode *inode;
	char *name;
	int error, fd;

561 562 563
	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
J
Jeff Dike 已提交
564
		goto out;
565
	}
L
Linus Torvalds 已提交
566 567

	error = -ENOMEM;
A
Al Viro 已提交
568
	name = dentry_name(dentry);
J
Jeff Dike 已提交
569
	if (name == NULL)
L
Linus Torvalds 已提交
570 571 572 573 574 575
		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);
576
	if (fd < 0)
L
Linus Torvalds 已提交
577
		error = fd;
578
	else
A
Al Viro 已提交
579
		error = read_name(inode, name);
L
Linus Torvalds 已提交
580

581
	__putname(name);
J
Jeff Dike 已提交
582
	if (error)
L
Linus Torvalds 已提交
583 584 585 586 587
		goto out_put;

	HOSTFS_I(inode)->fd = fd;
	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
	d_instantiate(dentry, inode);
J
Jeff Dike 已提交
588
	return 0;
L
Linus Torvalds 已提交
589 590 591 592

 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
593
	return error;
L
Linus Torvalds 已提交
594 595 596
}

struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
J
Jeff Dike 已提交
597
			     struct nameidata *nd)
L
Linus Torvalds 已提交
598 599 600 601 602
{
	struct inode *inode;
	char *name;
	int err;

603 604 605
	inode = hostfs_iget(ino->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
L
Linus Torvalds 已提交
606
		goto out;
607
	}
L
Linus Torvalds 已提交
608 609

	err = -ENOMEM;
A
Al Viro 已提交
610
	name = dentry_name(dentry);
J
Jeff Dike 已提交
611
	if (name == NULL)
L
Linus Torvalds 已提交
612 613 614
		goto out_put;

	err = read_name(inode, name);
A
Al Viro 已提交
615

616
	__putname(name);
J
Jeff Dike 已提交
617
	if (err == -ENOENT) {
L
Linus Torvalds 已提交
618 619 620
		iput(inode);
		inode = NULL;
	}
J
Jeff Dike 已提交
621
	else if (err)
L
Linus Torvalds 已提交
622 623 624
		goto out_put;

	d_add(dentry, inode);
J
Jeff Dike 已提交
625
	return NULL;
L
Linus Torvalds 已提交
626 627 628 629

 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
630
	return ERR_PTR(err);
L
Linus Torvalds 已提交
631 632 633 634
}

int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
{
J
Jeff Dike 已提交
635 636
	char *from_name, *to_name;
	int err;
L
Linus Torvalds 已提交
637

A
Al Viro 已提交
638
	if ((from_name = dentry_name(from)) == NULL)
J
Jeff Dike 已提交
639
		return -ENOMEM;
A
Al Viro 已提交
640
	to_name = dentry_name(to);
J
Jeff Dike 已提交
641
	if (to_name == NULL) {
642
		__putname(from_name);
J
Jeff Dike 已提交
643
		return -ENOMEM;
L
Linus Torvalds 已提交
644
	}
J
Jeff Dike 已提交
645
	err = link_file(to_name, from_name);
646 647
	__putname(from_name);
	__putname(to_name);
J
Jeff Dike 已提交
648
	return err;
L
Linus Torvalds 已提交
649 650 651 652 653 654 655
}

int hostfs_unlink(struct inode *ino, struct dentry *dentry)
{
	char *file;
	int err;

J
Jeff Dike 已提交
656
	if (append)
J
Jeff Dike 已提交
657
		return -EPERM;
L
Linus Torvalds 已提交
658

A
Al Viro 已提交
659 660 661
	if ((file = dentry_name(dentry)) == NULL)
		return -ENOMEM;

L
Linus Torvalds 已提交
662
	err = unlink_file(file);
663
	__putname(file);
J
Jeff Dike 已提交
664
	return err;
L
Linus Torvalds 已提交
665 666 667 668 669 670 671
}

int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
{
	char *file;
	int err;

A
Al Viro 已提交
672
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
673
		return -ENOMEM;
L
Linus Torvalds 已提交
674
	err = make_symlink(file, to);
675
	__putname(file);
J
Jeff Dike 已提交
676
	return err;
L
Linus Torvalds 已提交
677 678
}

679
int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
L
Linus Torvalds 已提交
680 681 682 683
{
	char *file;
	int err;

A
Al Viro 已提交
684
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
685
		return -ENOMEM;
L
Linus Torvalds 已提交
686
	err = do_mkdir(file, mode);
687
	__putname(file);
J
Jeff Dike 已提交
688
	return err;
L
Linus Torvalds 已提交
689 690 691 692 693 694 695
}

int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
{
	char *file;
	int err;

A
Al Viro 已提交
696
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
697
		return -ENOMEM;
L
Linus Torvalds 已提交
698
	err = do_rmdir(file);
699
	__putname(file);
J
Jeff Dike 已提交
700
	return err;
L
Linus Torvalds 已提交
701 702
}

A
Al Viro 已提交
703
static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
L
Linus Torvalds 已提交
704 705 706
{
	struct inode *inode;
	char *name;
707
	int err;
L
Linus Torvalds 已提交
708

709 710 711
	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
L
Linus Torvalds 已提交
712
		goto out;
713
	}
L
Linus Torvalds 已提交
714 715

	err = -ENOMEM;
A
Al Viro 已提交
716
	name = dentry_name(dentry);
J
Jeff Dike 已提交
717
	if (name == NULL)
L
Linus Torvalds 已提交
718 719 720
		goto out_put;

	init_special_inode(inode, mode, dev);
J
Johannes Stezenbach 已提交
721
	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
722
	if (!err)
L
Linus Torvalds 已提交
723 724 725
		goto out_free;

	err = read_name(inode, name);
726
	__putname(name);
A
Al Viro 已提交
727 728
	if (err)
		goto out_put;
J
Jeff Dike 已提交
729
	if (err)
L
Linus Torvalds 已提交
730 731 732
		goto out_put;

	d_instantiate(dentry, inode);
J
Jeff Dike 已提交
733
	return 0;
L
Linus Torvalds 已提交
734 735

 out_free:
736
	__putname(name);
L
Linus Torvalds 已提交
737 738 739
 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
740
	return err;
L
Linus Torvalds 已提交
741 742 743 744 745 746 747 748
}

int hostfs_rename(struct inode *from_ino, struct dentry *from,
		  struct inode *to_ino, struct dentry *to)
{
	char *from_name, *to_name;
	int err;

A
Al Viro 已提交
749
	if ((from_name = dentry_name(from)) == NULL)
J
Jeff Dike 已提交
750
		return -ENOMEM;
A
Al Viro 已提交
751
	if ((to_name = dentry_name(to)) == NULL) {
752
		__putname(from_name);
J
Jeff Dike 已提交
753
		return -ENOMEM;
L
Linus Torvalds 已提交
754 755
	}
	err = rename_file(from_name, to_name);
756 757
	__putname(from_name);
	__putname(to_name);
J
Jeff Dike 已提交
758
	return err;
L
Linus Torvalds 已提交
759 760
}

761
int hostfs_permission(struct inode *ino, int desired)
L
Linus Torvalds 已提交
762 763 764 765
{
	char *name;
	int r = 0, w = 0, x = 0, err;

766
	if (desired & MAY_NOT_BLOCK)
767 768
		return -ECHILD;

L
Linus Torvalds 已提交
769 770 771
	if (desired & MAY_READ) r = 1;
	if (desired & MAY_WRITE) w = 1;
	if (desired & MAY_EXEC) x = 1;
A
Al Viro 已提交
772
	name = inode_name(ino);
J
Jeff Dike 已提交
773 774
	if (name == NULL)
		return -ENOMEM;
L
Linus Torvalds 已提交
775 776

	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
J
Jeff Dike 已提交
777
	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
L
Linus Torvalds 已提交
778 779 780
		err = 0;
	else
		err = access_file(name, r, w, x);
781
	__putname(name);
J
Jeff Dike 已提交
782
	if (!err)
783
		err = generic_permission(ino, desired);
L
Linus Torvalds 已提交
784 785 786 787 788
	return err;
}

int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
{
C
Christoph Hellwig 已提交
789
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
790 791 792 793
	struct hostfs_iattr attrs;
	char *name;
	int err;

C
Christoph Hellwig 已提交
794
	int fd = HOSTFS_I(inode)->fd;
795

C
Christoph Hellwig 已提交
796
	err = inode_change_ok(inode, attr);
L
Linus Torvalds 已提交
797 798 799
	if (err)
		return err;

J
Jeff Dike 已提交
800
	if (append)
L
Linus Torvalds 已提交
801 802 803
		attr->ia_valid &= ~ATTR_SIZE;

	attrs.ia_valid = 0;
J
Jeff Dike 已提交
804
	if (attr->ia_valid & ATTR_MODE) {
L
Linus Torvalds 已提交
805 806 807
		attrs.ia_valid |= HOSTFS_ATTR_MODE;
		attrs.ia_mode = attr->ia_mode;
	}
J
Jeff Dike 已提交
808
	if (attr->ia_valid & ATTR_UID) {
L
Linus Torvalds 已提交
809 810 811
		attrs.ia_valid |= HOSTFS_ATTR_UID;
		attrs.ia_uid = attr->ia_uid;
	}
J
Jeff Dike 已提交
812
	if (attr->ia_valid & ATTR_GID) {
L
Linus Torvalds 已提交
813 814 815
		attrs.ia_valid |= HOSTFS_ATTR_GID;
		attrs.ia_gid = attr->ia_gid;
	}
J
Jeff Dike 已提交
816
	if (attr->ia_valid & ATTR_SIZE) {
L
Linus Torvalds 已提交
817 818 819
		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
		attrs.ia_size = attr->ia_size;
	}
J
Jeff Dike 已提交
820
	if (attr->ia_valid & ATTR_ATIME) {
L
Linus Torvalds 已提交
821 822 823
		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
		attrs.ia_atime = attr->ia_atime;
	}
J
Jeff Dike 已提交
824
	if (attr->ia_valid & ATTR_MTIME) {
L
Linus Torvalds 已提交
825 826 827
		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
		attrs.ia_mtime = attr->ia_mtime;
	}
J
Jeff Dike 已提交
828
	if (attr->ia_valid & ATTR_CTIME) {
L
Linus Torvalds 已提交
829 830 831
		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
		attrs.ia_ctime = attr->ia_ctime;
	}
J
Jeff Dike 已提交
832
	if (attr->ia_valid & ATTR_ATIME_SET) {
L
Linus Torvalds 已提交
833 834
		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
	}
J
Jeff Dike 已提交
835
	if (attr->ia_valid & ATTR_MTIME_SET) {
L
Linus Torvalds 已提交
836 837
		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
	}
A
Al Viro 已提交
838
	name = dentry_name(dentry);
J
Jeff Dike 已提交
839
	if (name == NULL)
J
Jeff Dike 已提交
840
		return -ENOMEM;
841
	err = set_attr(name, &attrs, fd);
842
	__putname(name);
J
Jeff Dike 已提交
843
	if (err)
J
Jeff Dike 已提交
844
		return err;
L
Linus Torvalds 已提交
845

C
Christoph Hellwig 已提交
846 847 848 849 850 851 852 853 854 855 856 857
	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;
L
Linus Torvalds 已提交
858 859
}

860
static const struct inode_operations hostfs_iops = {
L
Linus Torvalds 已提交
861 862 863 864 865 866 867 868 869 870 871 872
	.create		= hostfs_create,
	.link		= hostfs_link,
	.unlink		= hostfs_unlink,
	.symlink	= hostfs_symlink,
	.mkdir		= hostfs_mkdir,
	.rmdir		= hostfs_rmdir,
	.mknod		= hostfs_mknod,
	.rename		= hostfs_rename,
	.permission	= hostfs_permission,
	.setattr	= hostfs_setattr,
};

873
static const struct inode_operations hostfs_dir_iops = {
L
Linus Torvalds 已提交
874 875 876 877 878 879 880 881 882 883 884 885 886
	.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,
	.permission	= hostfs_permission,
	.setattr	= hostfs_setattr,
};

A
Al Viro 已提交
887 888 889 890 891 892 893
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) {
A
Al Viro 已提交
894
			err = hostfs_do_readlink(path, link, PATH_MAX);
A
Al Viro 已提交
895 896
			if (err == PATH_MAX)
				err = -E2BIG;
897
			__putname(path);
A
Al Viro 已提交
898 899 900 901 902 903 904
		}
		if (err < 0) {
			__putname(link);
			link = ERR_PTR(err);
		}
	} else {
		link = ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
905
	}
A
Al Viro 已提交
906 907 908 909 910 911 912 913 914 915

	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);
L
Linus Torvalds 已提交
916 917
}

A
Al Viro 已提交
918 919 920 921
static const struct inode_operations hostfs_link_iops = {
	.readlink	= generic_readlink,
	.follow_link	= hostfs_follow_link,
	.put_link	= hostfs_put_link,
L
Linus Torvalds 已提交
922 923 924 925 926
};

static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
{
	struct inode *root_inode;
927
	char *host_root_path, *req_root = d;
L
Linus Torvalds 已提交
928 929 930 931 932 933
	int err;

	sb->s_blocksize = 1024;
	sb->s_blocksize_bits = 10;
	sb->s_magic = HOSTFS_SUPER_MAGIC;
	sb->s_op = &hostfs_sbops;
A
Al Viro 已提交
934
	sb->s_d_op = &hostfs_dentry_ops;
935
	sb->s_maxbytes = MAX_LFS_FILESIZE;
L
Linus Torvalds 已提交
936

937
	/* NULL is printed as <NULL> by sprintf: avoid that. */
938 939
	if (req_root == NULL)
		req_root = "";
L
Linus Torvalds 已提交
940 941

	err = -ENOMEM;
942 943
	sb->s_fs_info = host_root_path =
		kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
J
Jeff Dike 已提交
944
	if (host_root_path == NULL)
L
Linus Torvalds 已提交
945 946
		goto out;

947
	sprintf(host_root_path, "%s/%s", root_ino, req_root);
L
Linus Torvalds 已提交
948

A
Al Viro 已提交
949 950
	root_inode = new_inode(sb);
	if (!root_inode)
951
		goto out;
L
Linus Torvalds 已提交
952

953 954 955
	err = read_name(root_inode, host_root_path);
	if (err)
		goto out_put;
A
Al Viro 已提交
956

957
	if (S_ISLNK(root_inode->i_mode)) {
A
Al Viro 已提交
958 959 960 961 962 963
		char *name = follow_link(host_root_path);
		if (IS_ERR(name))
			err = PTR_ERR(name);
		else
			err = read_name(root_inode, name);
		kfree(name);
964 965
		if (err)
			goto out_put;
A
Al Viro 已提交
966
	}
L
Linus Torvalds 已提交
967 968 969

	err = -ENOMEM;
	sb->s_root = d_alloc_root(root_inode);
J
Jeff Dike 已提交
970
	if (sb->s_root == NULL)
L
Linus Torvalds 已提交
971 972
		goto out_put;

J
Jeff Dike 已提交
973
	return 0;
L
Linus Torvalds 已提交
974

J
Jeff Dike 已提交
975 976 977 978
out_put:
	iput(root_inode);
out:
	return err;
L
Linus Torvalds 已提交
979 980
}

A
Al Viro 已提交
981
static struct dentry *hostfs_read_sb(struct file_system_type *type,
982
			  int flags, const char *dev_name,
A
Al Viro 已提交
983
			  void *data)
L
Linus Torvalds 已提交
984
{
A
Al Viro 已提交
985
	return mount_nodev(type, flags, data, hostfs_fill_sb_common);
L
Linus Torvalds 已提交
986 987
}

988 989 990 991 992 993
static void hostfs_kill_sb(struct super_block *s)
{
	kill_anon_super(s);
	kfree(s->s_fs_info);
}

L
Linus Torvalds 已提交
994 995 996
static struct file_system_type hostfs_type = {
	.owner 		= THIS_MODULE,
	.name 		= "hostfs",
A
Al Viro 已提交
997
	.mount	 	= hostfs_read_sb,
998
	.kill_sb	= hostfs_kill_sb,
L
Linus Torvalds 已提交
999 1000 1001 1002 1003
	.fs_flags 	= 0,
};

static int __init init_hostfs(void)
{
J
Jeff Dike 已提交
1004
	return register_filesystem(&hostfs_type);
L
Linus Torvalds 已提交
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
}

static void __exit exit_hostfs(void)
{
	unregister_filesystem(&hostfs_type);
}

module_init(init_hostfs)
module_exit(exit_hostfs)
MODULE_LICENSE("GPL");