1 | /* |
2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL |
4 | * |
5 | * Ported the filesystem routines to 2.5. |
6 | * 2003-02-10 Petr Baudis <pasky@ucw.cz> |
7 | */ |
8 | |
9 | #include <linux/fs.h> |
10 | #include <linux/magic.h> |
11 | #include <linux/module.h> |
12 | #include <linux/mm.h> |
13 | #include <linux/pagemap.h> |
14 | #include <linux/statfs.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/seq_file.h> |
17 | #include <linux/writeback.h> |
18 | #include <linux/mount.h> |
19 | #include <linux/namei.h> |
20 | #include "hostfs.h" |
21 | #include <init.h> |
22 | #include <kern.h> |
23 | |
24 | struct hostfs_inode_info { |
25 | int fd; |
26 | fmode_t mode; |
27 | struct inode vfs_inode; |
28 | struct mutex open_mutex; |
29 | dev_t dev; |
30 | }; |
31 | |
32 | static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) |
33 | { |
34 | return list_entry(inode, struct hostfs_inode_info, vfs_inode); |
35 | } |
36 | |
37 | #define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file)) |
38 | |
39 | static struct kmem_cache *hostfs_inode_cache; |
40 | |
41 | /* Changed in hostfs_args before the kernel starts running */ |
42 | static char *root_ino = "" ; |
43 | static int append = 0; |
44 | |
45 | static const struct inode_operations hostfs_iops; |
46 | static const struct inode_operations hostfs_dir_iops; |
47 | static const struct inode_operations hostfs_link_iops; |
48 | |
49 | #ifndef MODULE |
50 | static int __init hostfs_args(char *options, int *add) |
51 | { |
52 | char *ptr; |
53 | |
54 | ptr = strchr(options, ','); |
55 | if (ptr != NULL) |
56 | *ptr++ = '\0'; |
57 | if (*options != '\0') |
58 | root_ino = options; |
59 | |
60 | options = ptr; |
61 | while (options) { |
62 | ptr = strchr(options, ','); |
63 | if (ptr != NULL) |
64 | *ptr++ = '\0'; |
65 | if (*options != '\0') { |
66 | if (!strcmp(options, "append" )) |
67 | append = 1; |
68 | else printf("hostfs_args - unsupported option - %s\n" , |
69 | options); |
70 | } |
71 | options = ptr; |
72 | } |
73 | return 0; |
74 | } |
75 | |
76 | __uml_setup("hostfs=" , hostfs_args, |
77 | "hostfs=<root dir>,<flags>,...\n" |
78 | " This is used to set hostfs parameters. The root directory argument\n" |
79 | " is used to confine all hostfs mounts to within the specified directory\n" |
80 | " tree on the host. If this isn't specified, then a user inside UML can\n" |
81 | " mount anything on the host that's accessible to the user that's running\n" |
82 | " it.\n" |
83 | " The only flag currently supported is 'append', which specifies that all\n" |
84 | " files opened by hostfs will be opened in append mode.\n\n" |
85 | ); |
86 | #endif |
87 | |
88 | static char *__dentry_name(struct dentry *dentry, char *name) |
89 | { |
90 | char *p = dentry_path_raw(dentry, name, PATH_MAX); |
91 | char *root; |
92 | size_t len; |
93 | |
94 | root = dentry->d_sb->s_fs_info; |
95 | len = strlen(root); |
96 | if (IS_ERR(ptr: p)) { |
97 | __putname(name); |
98 | return NULL; |
99 | } |
100 | |
101 | /* |
102 | * This function relies on the fact that dentry_path_raw() will place |
103 | * the path name at the end of the provided buffer. |
104 | */ |
105 | BUG_ON(p + strlen(p) + 1 != name + PATH_MAX); |
106 | |
107 | strscpy(p: name, q: root, PATH_MAX); |
108 | if (len > p - name) { |
109 | __putname(name); |
110 | return NULL; |
111 | } |
112 | |
113 | if (p > name + len) |
114 | strcpy(p: name + len, q: p); |
115 | |
116 | return name; |
117 | } |
118 | |
119 | static char *dentry_name(struct dentry *dentry) |
120 | { |
121 | char *name = __getname(); |
122 | if (!name) |
123 | return NULL; |
124 | |
125 | return __dentry_name(dentry, name); |
126 | } |
127 | |
128 | static char *inode_name(struct inode *ino) |
129 | { |
130 | struct dentry *dentry; |
131 | char *name; |
132 | |
133 | dentry = d_find_alias(ino); |
134 | if (!dentry) |
135 | return NULL; |
136 | |
137 | name = dentry_name(dentry); |
138 | |
139 | dput(dentry); |
140 | |
141 | return name; |
142 | } |
143 | |
144 | static char *follow_link(char *link) |
145 | { |
146 | char *name, *resolved, *end; |
147 | int n; |
148 | |
149 | name = kmalloc(PATH_MAX, GFP_KERNEL); |
150 | if (!name) { |
151 | n = -ENOMEM; |
152 | goto out_free; |
153 | } |
154 | |
155 | n = hostfs_do_readlink(file: link, buf: name, PATH_MAX); |
156 | if (n < 0) |
157 | goto out_free; |
158 | else if (n == PATH_MAX) { |
159 | n = -E2BIG; |
160 | goto out_free; |
161 | } |
162 | |
163 | if (*name == '/') |
164 | return name; |
165 | |
166 | end = strrchr(link, '/'); |
167 | if (end == NULL) |
168 | return name; |
169 | |
170 | *(end + 1) = '\0'; |
171 | |
172 | resolved = kasprintf(GFP_KERNEL, fmt: "%s%s" , link, name); |
173 | if (resolved == NULL) { |
174 | n = -ENOMEM; |
175 | goto out_free; |
176 | } |
177 | |
178 | kfree(objp: name); |
179 | return resolved; |
180 | |
181 | out_free: |
182 | kfree(objp: name); |
183 | return ERR_PTR(error: n); |
184 | } |
185 | |
186 | static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf) |
187 | { |
188 | /* |
189 | * do_statfs uses struct statfs64 internally, but the linux kernel |
190 | * struct statfs still has 32-bit versions for most of these fields, |
191 | * so we convert them here |
192 | */ |
193 | int err; |
194 | long long f_blocks; |
195 | long long f_bfree; |
196 | long long f_bavail; |
197 | long long f_files; |
198 | long long f_ffree; |
199 | |
200 | err = do_statfs(root: dentry->d_sb->s_fs_info, |
201 | bsize_out: &sf->f_bsize, blocks_out: &f_blocks, bfree_out: &f_bfree, bavail_out: &f_bavail, files_out: &f_files, |
202 | ffree_out: &f_ffree, fsid_out: &sf->f_fsid, fsid_size: sizeof(sf->f_fsid), |
203 | namelen_out: &sf->f_namelen); |
204 | if (err) |
205 | return err; |
206 | sf->f_blocks = f_blocks; |
207 | sf->f_bfree = f_bfree; |
208 | sf->f_bavail = f_bavail; |
209 | sf->f_files = f_files; |
210 | sf->f_ffree = f_ffree; |
211 | sf->f_type = HOSTFS_SUPER_MAGIC; |
212 | return 0; |
213 | } |
214 | |
215 | static struct inode *hostfs_alloc_inode(struct super_block *sb) |
216 | { |
217 | struct hostfs_inode_info *hi; |
218 | |
219 | hi = alloc_inode_sb(sb, cache: hostfs_inode_cache, GFP_KERNEL_ACCOUNT); |
220 | if (hi == NULL) |
221 | return NULL; |
222 | hi->fd = -1; |
223 | hi->mode = 0; |
224 | hi->dev = 0; |
225 | inode_init_once(&hi->vfs_inode); |
226 | mutex_init(&hi->open_mutex); |
227 | return &hi->vfs_inode; |
228 | } |
229 | |
230 | static void hostfs_evict_inode(struct inode *inode) |
231 | { |
232 | truncate_inode_pages_final(&inode->i_data); |
233 | clear_inode(inode); |
234 | if (HOSTFS_I(inode)->fd != -1) { |
235 | close_file(stream: &HOSTFS_I(inode)->fd); |
236 | HOSTFS_I(inode)->fd = -1; |
237 | HOSTFS_I(inode)->dev = 0; |
238 | } |
239 | } |
240 | |
241 | static void hostfs_free_inode(struct inode *inode) |
242 | { |
243 | kmem_cache_free(s: hostfs_inode_cache, objp: HOSTFS_I(inode)); |
244 | } |
245 | |
246 | static int hostfs_show_options(struct seq_file *seq, struct dentry *root) |
247 | { |
248 | const char *root_path = root->d_sb->s_fs_info; |
249 | size_t offset = strlen(root_ino) + 1; |
250 | |
251 | if (strlen(root_path) > offset) |
252 | seq_show_option(m: seq, name: root_path + offset, NULL); |
253 | |
254 | if (append) |
255 | seq_puts(m: seq, s: ",append" ); |
256 | |
257 | return 0; |
258 | } |
259 | |
260 | static const struct super_operations hostfs_sbops = { |
261 | .alloc_inode = hostfs_alloc_inode, |
262 | .free_inode = hostfs_free_inode, |
263 | .drop_inode = generic_delete_inode, |
264 | .evict_inode = hostfs_evict_inode, |
265 | .statfs = hostfs_statfs, |
266 | .show_options = hostfs_show_options, |
267 | }; |
268 | |
269 | static int hostfs_readdir(struct file *file, struct dir_context *ctx) |
270 | { |
271 | void *dir; |
272 | char *name; |
273 | unsigned long long next, ino; |
274 | int error, len; |
275 | unsigned int type; |
276 | |
277 | name = dentry_name(dentry: file->f_path.dentry); |
278 | if (name == NULL) |
279 | return -ENOMEM; |
280 | dir = open_dir(path: name, err_out: &error); |
281 | __putname(name); |
282 | if (dir == NULL) |
283 | return -error; |
284 | next = ctx->pos; |
285 | seek_dir(stream: dir, pos: next); |
286 | while ((name = read_dir(stream: dir, pos_out: &next, ino_out: &ino, len_out: &len, type_out: &type)) != NULL) { |
287 | if (!dir_emit(ctx, name, namelen: len, ino, type)) |
288 | break; |
289 | ctx->pos = next; |
290 | } |
291 | close_dir(stream: dir); |
292 | return 0; |
293 | } |
294 | |
295 | static int hostfs_open(struct inode *ino, struct file *file) |
296 | { |
297 | char *name; |
298 | fmode_t mode; |
299 | int err; |
300 | int r, w, fd; |
301 | |
302 | mode = file->f_mode & (FMODE_READ | FMODE_WRITE); |
303 | if ((mode & HOSTFS_I(inode: ino)->mode) == mode) |
304 | return 0; |
305 | |
306 | mode |= HOSTFS_I(inode: ino)->mode; |
307 | |
308 | retry: |
309 | r = w = 0; |
310 | |
311 | if (mode & FMODE_READ) |
312 | r = 1; |
313 | if (mode & FMODE_WRITE) |
314 | r = w = 1; |
315 | |
316 | name = dentry_name(dentry: file_dentry(file)); |
317 | if (name == NULL) |
318 | return -ENOMEM; |
319 | |
320 | fd = open_file(path: name, r, w, append); |
321 | __putname(name); |
322 | if (fd < 0) |
323 | return fd; |
324 | |
325 | mutex_lock(&HOSTFS_I(ino)->open_mutex); |
326 | /* somebody else had handled it first? */ |
327 | if ((mode & HOSTFS_I(inode: ino)->mode) == mode) { |
328 | mutex_unlock(lock: &HOSTFS_I(inode: ino)->open_mutex); |
329 | close_file(stream: &fd); |
330 | return 0; |
331 | } |
332 | if ((mode | HOSTFS_I(inode: ino)->mode) != mode) { |
333 | mode |= HOSTFS_I(inode: ino)->mode; |
334 | mutex_unlock(lock: &HOSTFS_I(inode: ino)->open_mutex); |
335 | close_file(stream: &fd); |
336 | goto retry; |
337 | } |
338 | if (HOSTFS_I(inode: ino)->fd == -1) { |
339 | HOSTFS_I(inode: ino)->fd = fd; |
340 | } else { |
341 | err = replace_file(oldfd: fd, fd: HOSTFS_I(inode: ino)->fd); |
342 | close_file(stream: &fd); |
343 | if (err < 0) { |
344 | mutex_unlock(lock: &HOSTFS_I(inode: ino)->open_mutex); |
345 | return err; |
346 | } |
347 | } |
348 | HOSTFS_I(inode: ino)->mode = mode; |
349 | mutex_unlock(lock: &HOSTFS_I(inode: ino)->open_mutex); |
350 | |
351 | return 0; |
352 | } |
353 | |
354 | static int hostfs_file_release(struct inode *inode, struct file *file) |
355 | { |
356 | filemap_write_and_wait(mapping: inode->i_mapping); |
357 | |
358 | return 0; |
359 | } |
360 | |
361 | static int hostfs_fsync(struct file *file, loff_t start, loff_t end, |
362 | int datasync) |
363 | { |
364 | struct inode *inode = file->f_mapping->host; |
365 | int ret; |
366 | |
367 | ret = file_write_and_wait_range(file, start, end); |
368 | if (ret) |
369 | return ret; |
370 | |
371 | inode_lock(inode); |
372 | ret = fsync_file(fd: HOSTFS_I(inode)->fd, datasync); |
373 | inode_unlock(inode); |
374 | |
375 | return ret; |
376 | } |
377 | |
378 | static const struct file_operations hostfs_file_fops = { |
379 | .llseek = generic_file_llseek, |
380 | .splice_read = filemap_splice_read, |
381 | .splice_write = iter_file_splice_write, |
382 | .read_iter = generic_file_read_iter, |
383 | .write_iter = generic_file_write_iter, |
384 | .mmap = generic_file_mmap, |
385 | .open = hostfs_open, |
386 | .release = hostfs_file_release, |
387 | .fsync = hostfs_fsync, |
388 | }; |
389 | |
390 | static const struct file_operations hostfs_dir_fops = { |
391 | .llseek = generic_file_llseek, |
392 | .iterate_shared = hostfs_readdir, |
393 | .read = generic_read_dir, |
394 | .open = hostfs_open, |
395 | .fsync = hostfs_fsync, |
396 | }; |
397 | |
398 | static int hostfs_writepage(struct page *page, struct writeback_control *wbc) |
399 | { |
400 | struct address_space *mapping = page->mapping; |
401 | struct inode *inode = mapping->host; |
402 | char *buffer; |
403 | loff_t base = page_offset(page); |
404 | int count = PAGE_SIZE; |
405 | int end_index = inode->i_size >> PAGE_SHIFT; |
406 | int err; |
407 | |
408 | if (page->index >= end_index) |
409 | count = inode->i_size & (PAGE_SIZE-1); |
410 | |
411 | buffer = kmap_local_page(page); |
412 | |
413 | err = write_file(fd: HOSTFS_I(inode)->fd, offset: &base, buf: buffer, len: count); |
414 | if (err != count) { |
415 | if (err >= 0) |
416 | err = -EIO; |
417 | mapping_set_error(mapping, error: err); |
418 | goto out; |
419 | } |
420 | |
421 | if (base > inode->i_size) |
422 | inode->i_size = base; |
423 | |
424 | err = 0; |
425 | |
426 | out: |
427 | kunmap_local(buffer); |
428 | unlock_page(page); |
429 | |
430 | return err; |
431 | } |
432 | |
433 | static int hostfs_read_folio(struct file *file, struct folio *folio) |
434 | { |
435 | struct page *page = &folio->page; |
436 | char *buffer; |
437 | loff_t start = page_offset(page); |
438 | int bytes_read, ret = 0; |
439 | |
440 | buffer = kmap_local_page(page); |
441 | bytes_read = read_file(FILE_HOSTFS_I(file)->fd, offset: &start, buf: buffer, |
442 | PAGE_SIZE); |
443 | if (bytes_read < 0) { |
444 | ClearPageUptodate(page); |
445 | SetPageError(page); |
446 | ret = bytes_read; |
447 | goto out; |
448 | } |
449 | |
450 | memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read); |
451 | |
452 | ClearPageError(page); |
453 | SetPageUptodate(page); |
454 | |
455 | out: |
456 | flush_dcache_page(page); |
457 | kunmap_local(buffer); |
458 | unlock_page(page); |
459 | |
460 | return ret; |
461 | } |
462 | |
463 | static int hostfs_write_begin(struct file *file, struct address_space *mapping, |
464 | loff_t pos, unsigned len, |
465 | struct page **pagep, void **fsdata) |
466 | { |
467 | pgoff_t index = pos >> PAGE_SHIFT; |
468 | |
469 | *pagep = grab_cache_page_write_begin(mapping, index); |
470 | if (!*pagep) |
471 | return -ENOMEM; |
472 | return 0; |
473 | } |
474 | |
475 | static int hostfs_write_end(struct file *file, struct address_space *mapping, |
476 | loff_t pos, unsigned len, unsigned copied, |
477 | struct page *page, void *fsdata) |
478 | { |
479 | struct inode *inode = mapping->host; |
480 | void *buffer; |
481 | unsigned from = pos & (PAGE_SIZE - 1); |
482 | int err; |
483 | |
484 | buffer = kmap_local_page(page); |
485 | err = write_file(FILE_HOSTFS_I(file)->fd, offset: &pos, buf: buffer + from, len: copied); |
486 | kunmap_local(buffer); |
487 | |
488 | if (!PageUptodate(page) && err == PAGE_SIZE) |
489 | SetPageUptodate(page); |
490 | |
491 | /* |
492 | * If err > 0, write_file has added err to pos, so we are comparing |
493 | * i_size against the last byte written. |
494 | */ |
495 | if (err > 0 && (pos > inode->i_size)) |
496 | inode->i_size = pos; |
497 | unlock_page(page); |
498 | put_page(page); |
499 | |
500 | return err; |
501 | } |
502 | |
503 | static const struct address_space_operations hostfs_aops = { |
504 | .writepage = hostfs_writepage, |
505 | .read_folio = hostfs_read_folio, |
506 | .dirty_folio = filemap_dirty_folio, |
507 | .write_begin = hostfs_write_begin, |
508 | .write_end = hostfs_write_end, |
509 | }; |
510 | |
511 | static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st) |
512 | { |
513 | set_nlink(inode: ino, nlink: st->nlink); |
514 | i_uid_write(inode: ino, uid: st->uid); |
515 | i_gid_write(inode: ino, gid: st->gid); |
516 | inode_set_atime_to_ts(inode: ino, ts: (struct timespec64){ |
517 | st->atime.tv_sec, |
518 | st->atime.tv_nsec, |
519 | }); |
520 | inode_set_mtime_to_ts(inode: ino, ts: (struct timespec64){ |
521 | st->mtime.tv_sec, |
522 | st->mtime.tv_nsec, |
523 | }); |
524 | inode_set_ctime(inode: ino, sec: st->ctime.tv_sec, nsec: st->ctime.tv_nsec); |
525 | ino->i_size = st->size; |
526 | ino->i_blocks = st->blocks; |
527 | return 0; |
528 | } |
529 | |
530 | static int hostfs_inode_set(struct inode *ino, void *data) |
531 | { |
532 | struct hostfs_stat *st = data; |
533 | dev_t rdev; |
534 | |
535 | /* Reencode maj and min with the kernel encoding.*/ |
536 | rdev = MKDEV(st->maj, st->min); |
537 | |
538 | switch (st->mode & S_IFMT) { |
539 | case S_IFLNK: |
540 | ino->i_op = &hostfs_link_iops; |
541 | break; |
542 | case S_IFDIR: |
543 | ino->i_op = &hostfs_dir_iops; |
544 | ino->i_fop = &hostfs_dir_fops; |
545 | break; |
546 | case S_IFCHR: |
547 | case S_IFBLK: |
548 | case S_IFIFO: |
549 | case S_IFSOCK: |
550 | init_special_inode(ino, st->mode & S_IFMT, rdev); |
551 | ino->i_op = &hostfs_iops; |
552 | break; |
553 | case S_IFREG: |
554 | ino->i_op = &hostfs_iops; |
555 | ino->i_fop = &hostfs_file_fops; |
556 | ino->i_mapping->a_ops = &hostfs_aops; |
557 | break; |
558 | default: |
559 | return -EIO; |
560 | } |
561 | |
562 | HOSTFS_I(inode: ino)->dev = st->dev; |
563 | ino->i_ino = st->ino; |
564 | ino->i_mode = st->mode; |
565 | return hostfs_inode_update(ino, st); |
566 | } |
567 | |
568 | static int hostfs_inode_test(struct inode *inode, void *data) |
569 | { |
570 | const struct hostfs_stat *st = data; |
571 | |
572 | return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev; |
573 | } |
574 | |
575 | static struct inode *hostfs_iget(struct super_block *sb, char *name) |
576 | { |
577 | struct inode *inode; |
578 | struct hostfs_stat st; |
579 | int err = stat_file(path: name, p: &st, fd: -1); |
580 | |
581 | if (err) |
582 | return ERR_PTR(error: err); |
583 | |
584 | inode = iget5_locked(sb, st.ino, test: hostfs_inode_test, set: hostfs_inode_set, |
585 | &st); |
586 | if (!inode) |
587 | return ERR_PTR(error: -ENOMEM); |
588 | |
589 | if (inode->i_state & I_NEW) { |
590 | unlock_new_inode(inode); |
591 | } else { |
592 | spin_lock(lock: &inode->i_lock); |
593 | hostfs_inode_update(ino: inode, st: &st); |
594 | spin_unlock(lock: &inode->i_lock); |
595 | } |
596 | |
597 | return inode; |
598 | } |
599 | |
600 | static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir, |
601 | struct dentry *dentry, umode_t mode, bool excl) |
602 | { |
603 | struct inode *inode; |
604 | char *name; |
605 | int fd; |
606 | |
607 | name = dentry_name(dentry); |
608 | if (name == NULL) |
609 | return -ENOMEM; |
610 | |
611 | fd = file_create(name, mode: mode & 0777); |
612 | if (fd < 0) { |
613 | __putname(name); |
614 | return fd; |
615 | } |
616 | |
617 | inode = hostfs_iget(sb: dir->i_sb, name); |
618 | __putname(name); |
619 | if (IS_ERR(ptr: inode)) |
620 | return PTR_ERR(ptr: inode); |
621 | |
622 | HOSTFS_I(inode)->fd = fd; |
623 | HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE; |
624 | d_instantiate(dentry, inode); |
625 | return 0; |
626 | } |
627 | |
628 | static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, |
629 | unsigned int flags) |
630 | { |
631 | struct inode *inode = NULL; |
632 | char *name; |
633 | |
634 | name = dentry_name(dentry); |
635 | if (name == NULL) |
636 | return ERR_PTR(error: -ENOMEM); |
637 | |
638 | inode = hostfs_iget(sb: ino->i_sb, name); |
639 | __putname(name); |
640 | if (IS_ERR(ptr: inode)) { |
641 | if (PTR_ERR(ptr: inode) == -ENOENT) |
642 | inode = NULL; |
643 | else |
644 | return ERR_CAST(ptr: inode); |
645 | } |
646 | |
647 | return d_splice_alias(inode, dentry); |
648 | } |
649 | |
650 | static int hostfs_link(struct dentry *to, struct inode *ino, |
651 | struct dentry *from) |
652 | { |
653 | char *from_name, *to_name; |
654 | int err; |
655 | |
656 | if ((from_name = dentry_name(dentry: from)) == NULL) |
657 | return -ENOMEM; |
658 | to_name = dentry_name(dentry: to); |
659 | if (to_name == NULL) { |
660 | __putname(from_name); |
661 | return -ENOMEM; |
662 | } |
663 | err = link_file(to: to_name, from: from_name); |
664 | __putname(from_name); |
665 | __putname(to_name); |
666 | return err; |
667 | } |
668 | |
669 | static int hostfs_unlink(struct inode *ino, struct dentry *dentry) |
670 | { |
671 | char *file; |
672 | int err; |
673 | |
674 | if (append) |
675 | return -EPERM; |
676 | |
677 | if ((file = dentry_name(dentry)) == NULL) |
678 | return -ENOMEM; |
679 | |
680 | err = unlink_file(file); |
681 | __putname(file); |
682 | return err; |
683 | } |
684 | |
685 | static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino, |
686 | struct dentry *dentry, const char *to) |
687 | { |
688 | char *file; |
689 | int err; |
690 | |
691 | if ((file = dentry_name(dentry)) == NULL) |
692 | return -ENOMEM; |
693 | err = make_symlink(from: file, to); |
694 | __putname(file); |
695 | return err; |
696 | } |
697 | |
698 | static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, |
699 | struct dentry *dentry, umode_t mode) |
700 | { |
701 | char *file; |
702 | int err; |
703 | |
704 | if ((file = dentry_name(dentry)) == NULL) |
705 | return -ENOMEM; |
706 | err = do_mkdir(file, mode); |
707 | __putname(file); |
708 | return err; |
709 | } |
710 | |
711 | static int hostfs_rmdir(struct inode *ino, struct dentry *dentry) |
712 | { |
713 | char *file; |
714 | int err; |
715 | |
716 | if ((file = dentry_name(dentry)) == NULL) |
717 | return -ENOMEM; |
718 | err = hostfs_do_rmdir(file); |
719 | __putname(file); |
720 | return err; |
721 | } |
722 | |
723 | static int hostfs_mknod(struct mnt_idmap *idmap, struct inode *dir, |
724 | struct dentry *dentry, umode_t mode, dev_t dev) |
725 | { |
726 | struct inode *inode; |
727 | char *name; |
728 | int err; |
729 | |
730 | name = dentry_name(dentry); |
731 | if (name == NULL) |
732 | return -ENOMEM; |
733 | |
734 | err = do_mknod(file: name, mode, MAJOR(dev), MINOR(dev)); |
735 | if (err) { |
736 | __putname(name); |
737 | return err; |
738 | } |
739 | |
740 | inode = hostfs_iget(sb: dir->i_sb, name); |
741 | __putname(name); |
742 | if (IS_ERR(ptr: inode)) |
743 | return PTR_ERR(ptr: inode); |
744 | |
745 | d_instantiate(dentry, inode); |
746 | return 0; |
747 | } |
748 | |
749 | static int hostfs_rename2(struct mnt_idmap *idmap, |
750 | struct inode *old_dir, struct dentry *old_dentry, |
751 | struct inode *new_dir, struct dentry *new_dentry, |
752 | unsigned int flags) |
753 | { |
754 | char *old_name, *new_name; |
755 | int err; |
756 | |
757 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) |
758 | return -EINVAL; |
759 | |
760 | old_name = dentry_name(dentry: old_dentry); |
761 | if (old_name == NULL) |
762 | return -ENOMEM; |
763 | new_name = dentry_name(dentry: new_dentry); |
764 | if (new_name == NULL) { |
765 | __putname(old_name); |
766 | return -ENOMEM; |
767 | } |
768 | if (!flags) |
769 | err = rename_file(from: old_name, to: new_name); |
770 | else |
771 | err = rename2_file(from: old_name, to: new_name, flags); |
772 | |
773 | __putname(old_name); |
774 | __putname(new_name); |
775 | return err; |
776 | } |
777 | |
778 | static int hostfs_permission(struct mnt_idmap *idmap, |
779 | struct inode *ino, int desired) |
780 | { |
781 | char *name; |
782 | int r = 0, w = 0, x = 0, err; |
783 | |
784 | if (desired & MAY_NOT_BLOCK) |
785 | return -ECHILD; |
786 | |
787 | if (desired & MAY_READ) r = 1; |
788 | if (desired & MAY_WRITE) w = 1; |
789 | if (desired & MAY_EXEC) x = 1; |
790 | name = inode_name(ino); |
791 | if (name == NULL) |
792 | return -ENOMEM; |
793 | |
794 | if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) || |
795 | S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode)) |
796 | err = 0; |
797 | else |
798 | err = access_file(path: name, r, w, x); |
799 | __putname(name); |
800 | if (!err) |
801 | err = generic_permission(&nop_mnt_idmap, ino, desired); |
802 | return err; |
803 | } |
804 | |
805 | static int hostfs_setattr(struct mnt_idmap *idmap, |
806 | struct dentry *dentry, struct iattr *attr) |
807 | { |
808 | struct inode *inode = d_inode(dentry); |
809 | struct hostfs_iattr attrs; |
810 | char *name; |
811 | int err; |
812 | |
813 | int fd = HOSTFS_I(inode)->fd; |
814 | |
815 | err = setattr_prepare(&nop_mnt_idmap, dentry, attr); |
816 | if (err) |
817 | return err; |
818 | |
819 | if (append) |
820 | attr->ia_valid &= ~ATTR_SIZE; |
821 | |
822 | attrs.ia_valid = 0; |
823 | if (attr->ia_valid & ATTR_MODE) { |
824 | attrs.ia_valid |= HOSTFS_ATTR_MODE; |
825 | attrs.ia_mode = attr->ia_mode; |
826 | } |
827 | if (attr->ia_valid & ATTR_UID) { |
828 | attrs.ia_valid |= HOSTFS_ATTR_UID; |
829 | attrs.ia_uid = from_kuid(to: &init_user_ns, uid: attr->ia_uid); |
830 | } |
831 | if (attr->ia_valid & ATTR_GID) { |
832 | attrs.ia_valid |= HOSTFS_ATTR_GID; |
833 | attrs.ia_gid = from_kgid(to: &init_user_ns, gid: attr->ia_gid); |
834 | } |
835 | if (attr->ia_valid & ATTR_SIZE) { |
836 | attrs.ia_valid |= HOSTFS_ATTR_SIZE; |
837 | attrs.ia_size = attr->ia_size; |
838 | } |
839 | if (attr->ia_valid & ATTR_ATIME) { |
840 | attrs.ia_valid |= HOSTFS_ATTR_ATIME; |
841 | attrs.ia_atime = (struct hostfs_timespec) |
842 | { attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec }; |
843 | } |
844 | if (attr->ia_valid & ATTR_MTIME) { |
845 | attrs.ia_valid |= HOSTFS_ATTR_MTIME; |
846 | attrs.ia_mtime = (struct hostfs_timespec) |
847 | { attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec }; |
848 | } |
849 | if (attr->ia_valid & ATTR_CTIME) { |
850 | attrs.ia_valid |= HOSTFS_ATTR_CTIME; |
851 | attrs.ia_ctime = (struct hostfs_timespec) |
852 | { attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec }; |
853 | } |
854 | if (attr->ia_valid & ATTR_ATIME_SET) { |
855 | attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; |
856 | } |
857 | if (attr->ia_valid & ATTR_MTIME_SET) { |
858 | attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; |
859 | } |
860 | name = dentry_name(dentry); |
861 | if (name == NULL) |
862 | return -ENOMEM; |
863 | err = set_attr(file: name, attrs: &attrs, fd); |
864 | __putname(name); |
865 | if (err) |
866 | return err; |
867 | |
868 | if ((attr->ia_valid & ATTR_SIZE) && |
869 | attr->ia_size != i_size_read(inode)) |
870 | truncate_setsize(inode, newsize: attr->ia_size); |
871 | |
872 | setattr_copy(&nop_mnt_idmap, inode, attr); |
873 | mark_inode_dirty(inode); |
874 | return 0; |
875 | } |
876 | |
877 | static const struct inode_operations hostfs_iops = { |
878 | .permission = hostfs_permission, |
879 | .setattr = hostfs_setattr, |
880 | }; |
881 | |
882 | static const struct inode_operations hostfs_dir_iops = { |
883 | .create = hostfs_create, |
884 | .lookup = hostfs_lookup, |
885 | .link = hostfs_link, |
886 | .unlink = hostfs_unlink, |
887 | .symlink = hostfs_symlink, |
888 | .mkdir = hostfs_mkdir, |
889 | .rmdir = hostfs_rmdir, |
890 | .mknod = hostfs_mknod, |
891 | .rename = hostfs_rename2, |
892 | .permission = hostfs_permission, |
893 | .setattr = hostfs_setattr, |
894 | }; |
895 | |
896 | static const char *hostfs_get_link(struct dentry *dentry, |
897 | struct inode *inode, |
898 | struct delayed_call *done) |
899 | { |
900 | char *link; |
901 | if (!dentry) |
902 | return ERR_PTR(error: -ECHILD); |
903 | link = kmalloc(PATH_MAX, GFP_KERNEL); |
904 | if (link) { |
905 | char *path = dentry_name(dentry); |
906 | int err = -ENOMEM; |
907 | if (path) { |
908 | err = hostfs_do_readlink(file: path, buf: link, PATH_MAX); |
909 | if (err == PATH_MAX) |
910 | err = -E2BIG; |
911 | __putname(path); |
912 | } |
913 | if (err < 0) { |
914 | kfree(objp: link); |
915 | return ERR_PTR(error: err); |
916 | } |
917 | } else { |
918 | return ERR_PTR(error: -ENOMEM); |
919 | } |
920 | |
921 | set_delayed_call(call: done, fn: kfree_link, arg: link); |
922 | return link; |
923 | } |
924 | |
925 | static const struct inode_operations hostfs_link_iops = { |
926 | .get_link = hostfs_get_link, |
927 | }; |
928 | |
929 | static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) |
930 | { |
931 | struct inode *root_inode; |
932 | char *host_root_path, *req_root = d; |
933 | int err; |
934 | |
935 | sb->s_blocksize = 1024; |
936 | sb->s_blocksize_bits = 10; |
937 | sb->s_magic = HOSTFS_SUPER_MAGIC; |
938 | sb->s_op = &hostfs_sbops; |
939 | sb->s_d_op = &simple_dentry_operations; |
940 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
941 | err = super_setup_bdi(sb); |
942 | if (err) |
943 | return err; |
944 | |
945 | /* NULL is printed as '(null)' by printf(): avoid that. */ |
946 | if (req_root == NULL) |
947 | req_root = "" ; |
948 | |
949 | sb->s_fs_info = host_root_path = |
950 | kasprintf(GFP_KERNEL, fmt: "%s/%s" , root_ino, req_root); |
951 | if (host_root_path == NULL) |
952 | return -ENOMEM; |
953 | |
954 | root_inode = hostfs_iget(sb, name: host_root_path); |
955 | if (IS_ERR(ptr: root_inode)) |
956 | return PTR_ERR(ptr: root_inode); |
957 | |
958 | if (S_ISLNK(root_inode->i_mode)) { |
959 | char *name; |
960 | |
961 | iput(root_inode); |
962 | name = follow_link(link: host_root_path); |
963 | if (IS_ERR(ptr: name)) |
964 | return PTR_ERR(ptr: name); |
965 | |
966 | root_inode = hostfs_iget(sb, name); |
967 | kfree(objp: name); |
968 | if (IS_ERR(ptr: root_inode)) |
969 | return PTR_ERR(ptr: root_inode); |
970 | } |
971 | |
972 | sb->s_root = d_make_root(root_inode); |
973 | if (sb->s_root == NULL) |
974 | return -ENOMEM; |
975 | |
976 | return 0; |
977 | } |
978 | |
979 | static struct dentry *hostfs_read_sb(struct file_system_type *type, |
980 | int flags, const char *dev_name, |
981 | void *data) |
982 | { |
983 | return mount_nodev(fs_type: type, flags, data, fill_super: hostfs_fill_sb_common); |
984 | } |
985 | |
986 | static void hostfs_kill_sb(struct super_block *s) |
987 | { |
988 | kill_anon_super(sb: s); |
989 | kfree(objp: s->s_fs_info); |
990 | } |
991 | |
992 | static struct file_system_type hostfs_type = { |
993 | .owner = THIS_MODULE, |
994 | .name = "hostfs" , |
995 | .mount = hostfs_read_sb, |
996 | .kill_sb = hostfs_kill_sb, |
997 | .fs_flags = 0, |
998 | }; |
999 | MODULE_ALIAS_FS("hostfs" ); |
1000 | |
1001 | static int __init init_hostfs(void) |
1002 | { |
1003 | hostfs_inode_cache = KMEM_CACHE(hostfs_inode_info, 0); |
1004 | if (!hostfs_inode_cache) |
1005 | return -ENOMEM; |
1006 | return register_filesystem(&hostfs_type); |
1007 | } |
1008 | |
1009 | static void __exit exit_hostfs(void) |
1010 | { |
1011 | unregister_filesystem(&hostfs_type); |
1012 | kmem_cache_destroy(s: hostfs_inode_cache); |
1013 | } |
1014 | |
1015 | module_init(init_hostfs) |
1016 | module_exit(exit_hostfs) |
1017 | MODULE_LICENSE("GPL" ); |
1018 | |