11da177e4SLinus Torvalds /* 2f1adc05eSJeff Dike * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 31da177e4SLinus Torvalds * Licensed under the GPL 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Ported the filesystem routines to 2.5. 61da177e4SLinus Torvalds * 2003-02-10 Petr Baudis <pasky@ucw.cz> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/fs.h> 102b3b9bb0SJames Hogan #include <linux/magic.h> 111da177e4SLinus Torvalds #include <linux/module.h> 1284b3db04SJeff Dike #include <linux/mm.h> 131da177e4SLinus Torvalds #include <linux/pagemap.h> 141da177e4SLinus Torvalds #include <linux/statfs.h> 155a0e3ad6STejun Heo #include <linux/slab.h> 16dd2cc4dfSMiklos Szeredi #include <linux/seq_file.h> 17187c82cbSMatthew Wilcox (Oracle) #include <linux/writeback.h> 186966a977SJiri Kosina #include <linux/mount.h> 19d0352d3eSAl Viro #include <linux/namei.h> 201da177e4SLinus Torvalds #include "hostfs.h" 2137185b33SAl Viro #include <init.h> 2237185b33SAl Viro #include <kern.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds struct hostfs_inode_info { 251da177e4SLinus Torvalds int fd; 26aeb5d727SAl Viro fmode_t mode; 271da177e4SLinus Torvalds struct inode vfs_inode; 2869886e67SRichard Weinberger struct mutex open_mutex; 29*74ce793bSMickaël Salaün dev_t dev; 301da177e4SLinus Torvalds }; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) 331da177e4SLinus Torvalds { 34f1adc05eSJeff Dike return list_entry(inode, struct hostfs_inode_info, vfs_inode); 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 37496ad9aaSAl Viro #define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file)) 381da177e4SLinus Torvalds 39a15f1e41SJohannes Berg static struct kmem_cache *hostfs_inode_cache; 40a15f1e41SJohannes Berg 411da177e4SLinus Torvalds /* Changed in hostfs_args before the kernel starts running */ 42a6eb0be6SPaolo 'Blaisorblade' Giarrusso static char *root_ino = ""; 431da177e4SLinus Torvalds static int append = 0; 441da177e4SLinus Torvalds 4592e1d5beSArjan van de Ven static const struct inode_operations hostfs_iops; 4692e1d5beSArjan van de Ven static const struct inode_operations hostfs_dir_iops; 47d0352d3eSAl Viro static const struct inode_operations hostfs_link_iops; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds #ifndef MODULE 501da177e4SLinus Torvalds static int __init hostfs_args(char *options, int *add) 511da177e4SLinus Torvalds { 521da177e4SLinus Torvalds char *ptr; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds ptr = strchr(options, ','); 551da177e4SLinus Torvalds if (ptr != NULL) 561da177e4SLinus Torvalds *ptr++ = '\0'; 571da177e4SLinus Torvalds if (*options != '\0') 581da177e4SLinus Torvalds root_ino = options; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds options = ptr; 611da177e4SLinus Torvalds while (options) { 621da177e4SLinus Torvalds ptr = strchr(options, ','); 631da177e4SLinus Torvalds if (ptr != NULL) 641da177e4SLinus Torvalds *ptr++ = '\0'; 651da177e4SLinus Torvalds if (*options != '\0') { 661da177e4SLinus Torvalds if (!strcmp(options, "append")) 671da177e4SLinus Torvalds append = 1; 681da177e4SLinus Torvalds else printf("hostfs_args - unsupported option - %s\n", 691da177e4SLinus Torvalds options); 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds options = ptr; 721da177e4SLinus Torvalds } 73f1adc05eSJeff Dike return 0; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds __uml_setup("hostfs=", hostfs_args, 771da177e4SLinus Torvalds "hostfs=<root dir>,<flags>,...\n" 781da177e4SLinus Torvalds " This is used to set hostfs parameters. The root directory argument\n" 791da177e4SLinus Torvalds " is used to confine all hostfs mounts to within the specified directory\n" 801da177e4SLinus Torvalds " tree on the host. If this isn't specified, then a user inside UML can\n" 811da177e4SLinus Torvalds " mount anything on the host that's accessible to the user that's running\n" 821da177e4SLinus Torvalds " it.\n" 831da177e4SLinus Torvalds " The only flag currently supported is 'append', which specifies that all\n" 841da177e4SLinus Torvalds " files opened by hostfs will be opened in append mode.\n\n" 851da177e4SLinus Torvalds ); 861da177e4SLinus Torvalds #endif 871da177e4SLinus Torvalds 88e9193059SAl Viro static char *__dentry_name(struct dentry *dentry, char *name) 89e9193059SAl Viro { 90ec2447c2SNick Piggin char *p = dentry_path_raw(dentry, name, PATH_MAX); 91e9193059SAl Viro char *root; 92e9193059SAl Viro size_t len; 93e9193059SAl Viro 94e9193059SAl Viro root = dentry->d_sb->s_fs_info; 95e9193059SAl Viro len = strlen(root); 96e9193059SAl Viro if (IS_ERR(p)) { 97e9193059SAl Viro __putname(name); 98e9193059SAl Viro return NULL; 99e9193059SAl Viro } 100aad50b1eSRichard Weinberger 101aad50b1eSRichard Weinberger /* 102aad50b1eSRichard Weinberger * This function relies on the fact that dentry_path_raw() will place 103aad50b1eSRichard Weinberger * the path name at the end of the provided buffer. 104aad50b1eSRichard Weinberger */ 105aad50b1eSRichard Weinberger BUG_ON(p + strlen(p) + 1 != name + PATH_MAX); 106aad50b1eSRichard Weinberger 107b7f28a37SWolfram Sang strscpy(name, root, PATH_MAX); 108e9193059SAl Viro if (len > p - name) { 109e9193059SAl Viro __putname(name); 110e9193059SAl Viro return NULL; 111e9193059SAl Viro } 112c278e81bSRichard Weinberger 113c278e81bSRichard Weinberger if (p > name + len) 114c278e81bSRichard Weinberger strcpy(name + len, p); 115c278e81bSRichard Weinberger 116e9193059SAl Viro return name; 117e9193059SAl Viro } 118e9193059SAl Viro 119c5322220SAl Viro static char *dentry_name(struct dentry *dentry) 1201da177e4SLinus Torvalds { 121e9193059SAl Viro char *name = __getname(); 122e9193059SAl Viro if (!name) 123f1adc05eSJeff Dike return NULL; 1241da177e4SLinus Torvalds 1259dcc5e8aSJames Hogan return __dentry_name(dentry, name); 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 128c5322220SAl Viro static char *inode_name(struct inode *ino) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds struct dentry *dentry; 131ec2447c2SNick Piggin char *name; 132ec2447c2SNick Piggin 133ec2447c2SNick Piggin dentry = d_find_alias(ino); 134ec2447c2SNick Piggin if (!dentry) 135e9193059SAl Viro return NULL; 1361da177e4SLinus Torvalds 137ec2447c2SNick Piggin name = dentry_name(dentry); 138ec2447c2SNick Piggin 139ec2447c2SNick Piggin dput(dentry); 140ec2447c2SNick Piggin 141ec2447c2SNick Piggin return name; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static char *follow_link(char *link) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds char *name, *resolved, *end; 147b58c4e96SAndy Shevchenko int n; 1481da177e4SLinus Torvalds 1497f6c411cSAl Viro name = kmalloc(PATH_MAX, GFP_KERNEL); 1507c950992SRichard Weinberger if (!name) { 1511da177e4SLinus Torvalds n = -ENOMEM; 1527c950992SRichard Weinberger goto out_free; 1531da177e4SLinus Torvalds } 1547c950992SRichard Weinberger 1557c950992SRichard Weinberger n = hostfs_do_readlink(link, name, PATH_MAX); 1561da177e4SLinus Torvalds if (n < 0) 1571da177e4SLinus Torvalds goto out_free; 1587c950992SRichard Weinberger else if (n == PATH_MAX) { 1597c950992SRichard Weinberger n = -E2BIG; 1607c950992SRichard Weinberger goto out_free; 1617c950992SRichard Weinberger } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds if (*name == '/') 164f1adc05eSJeff Dike return name; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds end = strrchr(link, '/'); 1671da177e4SLinus Torvalds if (end == NULL) 168f1adc05eSJeff Dike return name; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds *(end + 1) = '\0'; 1711da177e4SLinus Torvalds 172b58c4e96SAndy Shevchenko resolved = kasprintf(GFP_KERNEL, "%s%s", link, name); 1731da177e4SLinus Torvalds if (resolved == NULL) { 1741da177e4SLinus Torvalds n = -ENOMEM; 1751da177e4SLinus Torvalds goto out_free; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1787f6c411cSAl Viro kfree(name); 179f1adc05eSJeff Dike return resolved; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds out_free: 1827f6c411cSAl Viro kfree(name); 183f1adc05eSJeff Dike return ERR_PTR(n); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1869e443bc3SJames Hogan static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf) 1871da177e4SLinus Torvalds { 18884b3db04SJeff Dike /* 18984b3db04SJeff Dike * do_statfs uses struct statfs64 internally, but the linux kernel 1901da177e4SLinus Torvalds * struct statfs still has 32-bit versions for most of these fields, 1911da177e4SLinus Torvalds * so we convert them here 1921da177e4SLinus Torvalds */ 1931da177e4SLinus Torvalds int err; 1941da177e4SLinus Torvalds long long f_blocks; 1951da177e4SLinus Torvalds long long f_bfree; 1961da177e4SLinus Torvalds long long f_bavail; 1971da177e4SLinus Torvalds long long f_files; 1981da177e4SLinus Torvalds long long f_ffree; 1991da177e4SLinus Torvalds 200601d2c38SAl Viro err = do_statfs(dentry->d_sb->s_fs_info, 2011da177e4SLinus Torvalds &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, 2021da177e4SLinus Torvalds &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), 2031b627d57SRichard Weinberger &sf->f_namelen); 204f1adc05eSJeff Dike if (err) 205f1adc05eSJeff Dike return err; 2061da177e4SLinus Torvalds sf->f_blocks = f_blocks; 2071da177e4SLinus Torvalds sf->f_bfree = f_bfree; 2081da177e4SLinus Torvalds sf->f_bavail = f_bavail; 2091da177e4SLinus Torvalds sf->f_files = f_files; 2101da177e4SLinus Torvalds sf->f_ffree = f_ffree; 2111da177e4SLinus Torvalds sf->f_type = HOSTFS_SUPER_MAGIC; 212f1adc05eSJeff Dike return 0; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds static struct inode *hostfs_alloc_inode(struct super_block *sb) 2161da177e4SLinus Torvalds { 2171da177e4SLinus Torvalds struct hostfs_inode_info *hi; 2181da177e4SLinus Torvalds 219fd60b288SMuchun Song hi = alloc_inode_sb(sb, hostfs_inode_cache, GFP_KERNEL_ACCOUNT); 2201da177e4SLinus Torvalds if (hi == NULL) 221f1adc05eSJeff Dike return NULL; 222601d2c38SAl Viro hi->fd = -1; 223371fdab1SJames Hogan hi->mode = 0; 224*74ce793bSMickaël Salaün hi->dev = 0; 2251da177e4SLinus Torvalds inode_init_once(&hi->vfs_inode); 22669886e67SRichard Weinberger mutex_init(&hi->open_mutex); 227f1adc05eSJeff Dike return &hi->vfs_inode; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 230e971a6d7SAl Viro static void hostfs_evict_inode(struct inode *inode) 2311da177e4SLinus Torvalds { 23291b0abe3SJohannes Weiner truncate_inode_pages_final(&inode->i_data); 233dbd5768fSJan Kara clear_inode(inode); 2341da177e4SLinus Torvalds if (HOSTFS_I(inode)->fd != -1) { 2351da177e4SLinus Torvalds close_file(&HOSTFS_I(inode)->fd); 2361da177e4SLinus Torvalds HOSTFS_I(inode)->fd = -1; 237*74ce793bSMickaël Salaün HOSTFS_I(inode)->dev = 0; 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 24108ccfc5cSAl Viro static void hostfs_free_inode(struct inode *inode) 242fa0d7e3dSNick Piggin { 243a15f1e41SJohannes Berg kmem_cache_free(hostfs_inode_cache, HOSTFS_I(inode)); 244fa0d7e3dSNick Piggin } 245fa0d7e3dSNick Piggin 24634c80b1dSAl Viro static int hostfs_show_options(struct seq_file *seq, struct dentry *root) 247dd2cc4dfSMiklos Szeredi { 24834c80b1dSAl Viro const char *root_path = root->d_sb->s_fs_info; 249dd2cc4dfSMiklos Szeredi size_t offset = strlen(root_ino) + 1; 250dd2cc4dfSMiklos Szeredi 251dd2cc4dfSMiklos Szeredi if (strlen(root_path) > offset) 252a068acf2SKees Cook seq_show_option(seq, root_path + offset, NULL); 253dd2cc4dfSMiklos Szeredi 2547f74a668SRichard Weinberger if (append) 2557f74a668SRichard Weinberger seq_puts(seq, ",append"); 2567f74a668SRichard Weinberger 257dd2cc4dfSMiklos Szeredi return 0; 258dd2cc4dfSMiklos Szeredi } 259dd2cc4dfSMiklos Szeredi 260ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations hostfs_sbops = { 2611da177e4SLinus Torvalds .alloc_inode = hostfs_alloc_inode, 26208ccfc5cSAl Viro .free_inode = hostfs_free_inode, 263*74ce793bSMickaël Salaün .drop_inode = generic_delete_inode, 264e971a6d7SAl Viro .evict_inode = hostfs_evict_inode, 2651da177e4SLinus Torvalds .statfs = hostfs_statfs, 266dd2cc4dfSMiklos Szeredi .show_options = hostfs_show_options, 2671da177e4SLinus Torvalds }; 2681da177e4SLinus Torvalds 2699e443bc3SJames Hogan static int hostfs_readdir(struct file *file, struct dir_context *ctx) 2701da177e4SLinus Torvalds { 2711da177e4SLinus Torvalds void *dir; 2721da177e4SLinus Torvalds char *name; 2731da177e4SLinus Torvalds unsigned long long next, ino; 2741da177e4SLinus Torvalds int error, len; 2753ee6bd8eSGeert Uytterhoeven unsigned int type; 2761da177e4SLinus Torvalds 277c5322220SAl Viro name = dentry_name(file->f_path.dentry); 278f1adc05eSJeff Dike if (name == NULL) 279f1adc05eSJeff Dike return -ENOMEM; 2801da177e4SLinus Torvalds dir = open_dir(name, &error); 281e9193059SAl Viro __putname(name); 282f1adc05eSJeff Dike if (dir == NULL) 283f1adc05eSJeff Dike return -error; 2848e28bc7eSAl Viro next = ctx->pos; 2850c9bd636SRichard Weinberger seek_dir(dir, next); 2863ee6bd8eSGeert Uytterhoeven while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) { 2878e28bc7eSAl Viro if (!dir_emit(ctx, name, len, ino, type)) 2888e28bc7eSAl Viro break; 2898e28bc7eSAl Viro ctx->pos = next; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds close_dir(dir); 292f1adc05eSJeff Dike return 0; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2954c6dcafcSRichard Weinberger static int hostfs_open(struct inode *ino, struct file *file) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds char *name; 298bd1052a2SRichard Weinberger fmode_t mode; 299f8ad850fSAl Viro int err; 300bd1052a2SRichard Weinberger int r, w, fd; 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds mode = file->f_mode & (FMODE_READ | FMODE_WRITE); 3031da177e4SLinus Torvalds if ((mode & HOSTFS_I(ino)->mode) == mode) 304f1adc05eSJeff Dike return 0; 3051da177e4SLinus Torvalds 306f8ad850fSAl Viro mode |= HOSTFS_I(ino)->mode; 3071da177e4SLinus Torvalds 308f8ad850fSAl Viro retry: 309a9d1958bSRichard Weinberger r = w = 0; 310a9d1958bSRichard Weinberger 311f8ad850fSAl Viro if (mode & FMODE_READ) 3121da177e4SLinus Torvalds r = 1; 313f8ad850fSAl Viro if (mode & FMODE_WRITE) 314112a5da7SRichard Weinberger r = w = 1; 3151da177e4SLinus Torvalds 316d692d397SAl Viro name = dentry_name(file_dentry(file)); 3171da177e4SLinus Torvalds if (name == NULL) 318f1adc05eSJeff Dike return -ENOMEM; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds fd = open_file(name, r, w, append); 321e9193059SAl Viro __putname(name); 322f1adc05eSJeff Dike if (fd < 0) 323f1adc05eSJeff Dike return fd; 324f8ad850fSAl Viro 32569886e67SRichard Weinberger mutex_lock(&HOSTFS_I(ino)->open_mutex); 326f8ad850fSAl Viro /* somebody else had handled it first? */ 327f8ad850fSAl Viro if ((mode & HOSTFS_I(ino)->mode) == mode) { 32869886e67SRichard Weinberger mutex_unlock(&HOSTFS_I(ino)->open_mutex); 329af955658SRichard Weinberger close_file(&fd); 330f8ad850fSAl Viro return 0; 331f8ad850fSAl Viro } 332f8ad850fSAl Viro if ((mode | HOSTFS_I(ino)->mode) != mode) { 333f8ad850fSAl Viro mode |= HOSTFS_I(ino)->mode; 33469886e67SRichard Weinberger mutex_unlock(&HOSTFS_I(ino)->open_mutex); 335f8ad850fSAl Viro close_file(&fd); 336f8ad850fSAl Viro goto retry; 337f8ad850fSAl Viro } 338f8ad850fSAl Viro if (HOSTFS_I(ino)->fd == -1) { 339f8ad850fSAl Viro HOSTFS_I(ino)->fd = fd; 340f8ad850fSAl Viro } else { 341f8ad850fSAl Viro err = replace_file(fd, HOSTFS_I(ino)->fd); 342f8ad850fSAl Viro close_file(&fd); 343f8ad850fSAl Viro if (err < 0) { 34469886e67SRichard Weinberger mutex_unlock(&HOSTFS_I(ino)->open_mutex); 345f8ad850fSAl Viro return err; 346f8ad850fSAl Viro } 347f8ad850fSAl Viro } 348f8ad850fSAl Viro HOSTFS_I(ino)->mode = mode; 34969886e67SRichard Weinberger mutex_unlock(&HOSTFS_I(ino)->open_mutex); 3501da177e4SLinus Torvalds 351f1adc05eSJeff Dike return 0; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 35465984ff9SRichard Weinberger static int hostfs_file_release(struct inode *inode, struct file *file) 35565984ff9SRichard Weinberger { 35665984ff9SRichard Weinberger filemap_write_and_wait(inode->i_mapping); 35765984ff9SRichard Weinberger 35865984ff9SRichard Weinberger return 0; 35965984ff9SRichard Weinberger } 36065984ff9SRichard Weinberger 3619e443bc3SJames Hogan static int hostfs_fsync(struct file *file, loff_t start, loff_t end, 3629e443bc3SJames Hogan int datasync) 3631da177e4SLinus Torvalds { 36402c24a82SJosef Bacik struct inode *inode = file->f_mapping->host; 36502c24a82SJosef Bacik int ret; 36602c24a82SJosef Bacik 3673b49c9a1SJeff Layton ret = file_write_and_wait_range(file, start, end); 36802c24a82SJosef Bacik if (ret) 36902c24a82SJosef Bacik return ret; 37002c24a82SJosef Bacik 3715955102cSAl Viro inode_lock(inode); 37202c24a82SJosef Bacik ret = fsync_file(HOSTFS_I(inode)->fd, datasync); 3735955102cSAl Viro inode_unlock(inode); 37402c24a82SJosef Bacik 37502c24a82SJosef Bacik return ret; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3784b6f5d20SArjan van de Ven static const struct file_operations hostfs_file_fops = { 3791da177e4SLinus Torvalds .llseek = generic_file_llseek, 3805ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 3811568cb0eSJohannes Berg .splice_write = iter_file_splice_write, 382aad4f8bbSAl Viro .read_iter = generic_file_read_iter, 3838174202bSAl Viro .write_iter = generic_file_write_iter, 3841da177e4SLinus Torvalds .mmap = generic_file_mmap, 3854c6dcafcSRichard Weinberger .open = hostfs_open, 38665984ff9SRichard Weinberger .release = hostfs_file_release, 3871da177e4SLinus Torvalds .fsync = hostfs_fsync, 3881da177e4SLinus Torvalds }; 3891da177e4SLinus Torvalds 3904b6f5d20SArjan van de Ven static const struct file_operations hostfs_dir_fops = { 3911da177e4SLinus Torvalds .llseek = generic_file_llseek, 392552a9d48SAl Viro .iterate_shared = hostfs_readdir, 3931da177e4SLinus Torvalds .read = generic_read_dir, 3944c6dcafcSRichard Weinberger .open = hostfs_open, 3954c6dcafcSRichard Weinberger .fsync = hostfs_fsync, 3961da177e4SLinus Torvalds }; 3971da177e4SLinus Torvalds 3989e443bc3SJames Hogan static int hostfs_writepage(struct page *page, struct writeback_control *wbc) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds struct address_space *mapping = page->mapping; 4011da177e4SLinus Torvalds struct inode *inode = mapping->host; 4021da177e4SLinus Torvalds char *buffer; 403af6aa1b9SRichard Weinberger loff_t base = page_offset(page); 40409cbfeafSKirill A. Shutemov int count = PAGE_SIZE; 40509cbfeafSKirill A. Shutemov int end_index = inode->i_size >> PAGE_SHIFT; 4061da177e4SLinus Torvalds int err; 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds if (page->index >= end_index) 40909cbfeafSKirill A. Shutemov count = inode->i_size & (PAGE_SIZE-1); 4101da177e4SLinus Torvalds 411e0820368SFabio M. De Francesco buffer = kmap_local_page(page); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count); 4141da177e4SLinus Torvalds if (err != count) { 415e775dfb3SMatthew Wilcox (Oracle) if (err >= 0) 416e775dfb3SMatthew Wilcox (Oracle) err = -EIO; 417e775dfb3SMatthew Wilcox (Oracle) mapping_set_error(mapping, err); 4181da177e4SLinus Torvalds goto out; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if (base > inode->i_size) 4221da177e4SLinus Torvalds inode->i_size = base; 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds err = 0; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds out: 427e0820368SFabio M. De Francesco kunmap_local(buffer); 4281da177e4SLinus Torvalds unlock_page(page); 429e0820368SFabio M. De Francesco 4301da177e4SLinus Torvalds return err; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4338f4fe249SMatthew Wilcox (Oracle) static int hostfs_read_folio(struct file *file, struct folio *folio) 4341da177e4SLinus Torvalds { 4358f4fe249SMatthew Wilcox (Oracle) struct page *page = &folio->page; 4361da177e4SLinus Torvalds char *buffer; 437af6aa1b9SRichard Weinberger loff_t start = page_offset(page); 438b86b413aSRichard Weinberger int bytes_read, ret = 0; 4391da177e4SLinus Torvalds 440e0820368SFabio M. De Francesco buffer = kmap_local_page(page); 44141761ddfSRichard Weinberger bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer, 44209cbfeafSKirill A. Shutemov PAGE_SIZE); 44341761ddfSRichard Weinberger if (bytes_read < 0) { 444b86b413aSRichard Weinberger ClearPageUptodate(page); 445b86b413aSRichard Weinberger SetPageError(page); 44641761ddfSRichard Weinberger ret = bytes_read; 44784b3db04SJeff Dike goto out; 44841761ddfSRichard Weinberger } 4491da177e4SLinus Torvalds 45009cbfeafSKirill A. Shutemov memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read); 4511da177e4SLinus Torvalds 452b86b413aSRichard Weinberger ClearPageError(page); 4531da177e4SLinus Torvalds SetPageUptodate(page); 454b86b413aSRichard Weinberger 4551da177e4SLinus Torvalds out: 456b86b413aSRichard Weinberger flush_dcache_page(page); 457e0820368SFabio M. De Francesco kunmap_local(buffer); 4581da177e4SLinus Torvalds unlock_page(page); 459e0820368SFabio M. De Francesco 46041761ddfSRichard Weinberger return ret; 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 4639e443bc3SJames Hogan static int hostfs_write_begin(struct file *file, struct address_space *mapping, 4649d6b0cd7SMatthew Wilcox (Oracle) loff_t pos, unsigned len, 465ae361ff4SNick Piggin struct page **pagep, void **fsdata) 4661da177e4SLinus Torvalds { 46709cbfeafSKirill A. Shutemov pgoff_t index = pos >> PAGE_SHIFT; 468ae361ff4SNick Piggin 469b7446e7cSMatthew Wilcox (Oracle) *pagep = grab_cache_page_write_begin(mapping, index); 470ae361ff4SNick Piggin if (!*pagep) 471ae361ff4SNick Piggin return -ENOMEM; 472ae361ff4SNick Piggin return 0; 473ae361ff4SNick Piggin } 474ae361ff4SNick Piggin 4759e443bc3SJames Hogan static int hostfs_write_end(struct file *file, struct address_space *mapping, 476ae361ff4SNick Piggin loff_t pos, unsigned len, unsigned copied, 477ae361ff4SNick Piggin struct page *page, void *fsdata) 478ae361ff4SNick Piggin { 479ae361ff4SNick Piggin struct inode *inode = mapping->host; 480ae361ff4SNick Piggin void *buffer; 48109cbfeafSKirill A. Shutemov unsigned from = pos & (PAGE_SIZE - 1); 4821da177e4SLinus Torvalds int err; 4831da177e4SLinus Torvalds 484e0820368SFabio M. De Francesco buffer = kmap_local_page(page); 485ae361ff4SNick Piggin err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied); 486e0820368SFabio M. De Francesco kunmap_local(buffer); 4871da177e4SLinus Torvalds 48809cbfeafSKirill A. Shutemov if (!PageUptodate(page) && err == PAGE_SIZE) 489ae361ff4SNick Piggin SetPageUptodate(page); 4901da177e4SLinus Torvalds 49184b3db04SJeff Dike /* 49284b3db04SJeff Dike * If err > 0, write_file has added err to pos, so we are comparing 493ae361ff4SNick Piggin * i_size against the last byte written. 494ae361ff4SNick Piggin */ 495ae361ff4SNick Piggin if (err > 0 && (pos > inode->i_size)) 496ae361ff4SNick Piggin inode->i_size = pos; 497ae361ff4SNick Piggin unlock_page(page); 49809cbfeafSKirill A. Shutemov put_page(page); 49930f04a4eSPaolo 'Blaisorblade' Giarrusso 500f1adc05eSJeff Dike return err; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds 503f5e54d6eSChristoph Hellwig static const struct address_space_operations hostfs_aops = { 5041da177e4SLinus Torvalds .writepage = hostfs_writepage, 5058f4fe249SMatthew Wilcox (Oracle) .read_folio = hostfs_read_folio, 506187c82cbSMatthew Wilcox (Oracle) .dirty_folio = filemap_dirty_folio, 507ae361ff4SNick Piggin .write_begin = hostfs_write_begin, 508ae361ff4SNick Piggin .write_end = hostfs_write_end, 5091da177e4SLinus Torvalds }; 5101da177e4SLinus Torvalds 511*74ce793bSMickaël Salaün static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st) 5121da177e4SLinus Torvalds { 513*74ce793bSMickaël Salaün set_nlink(ino, st->nlink); 514*74ce793bSMickaël Salaün i_uid_write(ino, st->uid); 515*74ce793bSMickaël Salaün i_gid_write(ino, st->gid); 516*74ce793bSMickaël Salaün ino->i_atime = 517*74ce793bSMickaël Salaün (struct timespec64){ st->atime.tv_sec, st->atime.tv_nsec }; 518*74ce793bSMickaël Salaün ino->i_mtime = 519*74ce793bSMickaël Salaün (struct timespec64){ st->mtime.tv_sec, st->mtime.tv_nsec }; 520*74ce793bSMickaël Salaün ino->i_ctime = 521*74ce793bSMickaël Salaün (struct timespec64){ st->ctime.tv_sec, st->ctime.tv_nsec }; 522*74ce793bSMickaël Salaün ino->i_size = st->size; 523*74ce793bSMickaël Salaün ino->i_blocks = st->blocks; 524*74ce793bSMickaël Salaün return 0; 525*74ce793bSMickaël Salaün } 526*74ce793bSMickaël Salaün 527*74ce793bSMickaël Salaün static int hostfs_inode_set(struct inode *ino, void *data) 528*74ce793bSMickaël Salaün { 529*74ce793bSMickaël Salaün struct hostfs_stat *st = data; 5304754b825SAl Viro dev_t rdev; 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds /* Reencode maj and min with the kernel encoding.*/ 533*74ce793bSMickaël Salaün rdev = MKDEV(st->maj, st->min); 5341da177e4SLinus Torvalds 535*74ce793bSMickaël Salaün switch (st->mode & S_IFMT) { 5364754b825SAl Viro case S_IFLNK: 537d0352d3eSAl Viro ino->i_op = &hostfs_link_iops; 5384754b825SAl Viro break; 5394754b825SAl Viro case S_IFDIR: 5404754b825SAl Viro ino->i_op = &hostfs_dir_iops; 5414754b825SAl Viro ino->i_fop = &hostfs_dir_fops; 5424754b825SAl Viro break; 5434754b825SAl Viro case S_IFCHR: 5444754b825SAl Viro case S_IFBLK: 5454754b825SAl Viro case S_IFIFO: 5464754b825SAl Viro case S_IFSOCK: 547*74ce793bSMickaël Salaün init_special_inode(ino, st->mode & S_IFMT, rdev); 5484754b825SAl Viro ino->i_op = &hostfs_iops; 5494754b825SAl Viro break; 5502ad2dca6SRichard Weinberger case S_IFREG: 5514754b825SAl Viro ino->i_op = &hostfs_iops; 5524754b825SAl Viro ino->i_fop = &hostfs_file_fops; 5534754b825SAl Viro ino->i_mapping->a_ops = &hostfs_aops; 5542ad2dca6SRichard Weinberger break; 5552ad2dca6SRichard Weinberger default: 5562ad2dca6SRichard Weinberger return -EIO; 5571da177e4SLinus Torvalds } 5584754b825SAl Viro 559*74ce793bSMickaël Salaün HOSTFS_I(ino)->dev = st->dev; 560*74ce793bSMickaël Salaün ino->i_ino = st->ino; 561*74ce793bSMickaël Salaün ino->i_mode = st->mode; 562*74ce793bSMickaël Salaün return hostfs_inode_update(ino, st); 563*74ce793bSMickaël Salaün } 564*74ce793bSMickaël Salaün 565*74ce793bSMickaël Salaün static int hostfs_inode_test(struct inode *inode, void *data) 566*74ce793bSMickaël Salaün { 567*74ce793bSMickaël Salaün const struct hostfs_stat *st = data; 568*74ce793bSMickaël Salaün 569*74ce793bSMickaël Salaün return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev; 570*74ce793bSMickaël Salaün } 571*74ce793bSMickaël Salaün 572*74ce793bSMickaël Salaün static struct inode *hostfs_iget(struct super_block *sb, char *name) 573*74ce793bSMickaël Salaün { 574*74ce793bSMickaël Salaün struct inode *inode; 575*74ce793bSMickaël Salaün struct hostfs_stat st; 576*74ce793bSMickaël Salaün int err = stat_file(name, &st, -1); 577*74ce793bSMickaël Salaün 578*74ce793bSMickaël Salaün if (err) 579*74ce793bSMickaël Salaün return ERR_PTR(err); 580*74ce793bSMickaël Salaün 581*74ce793bSMickaël Salaün inode = iget5_locked(sb, st.ino, hostfs_inode_test, hostfs_inode_set, 582*74ce793bSMickaël Salaün &st); 583*74ce793bSMickaël Salaün if (!inode) 584*74ce793bSMickaël Salaün return ERR_PTR(-ENOMEM); 585*74ce793bSMickaël Salaün 586*74ce793bSMickaël Salaün if (inode->i_state & I_NEW) { 587*74ce793bSMickaël Salaün unlock_new_inode(inode); 588*74ce793bSMickaël Salaün } else { 589*74ce793bSMickaël Salaün spin_lock(&inode->i_lock); 590*74ce793bSMickaël Salaün hostfs_inode_update(inode, &st); 591*74ce793bSMickaël Salaün spin_unlock(&inode->i_lock); 592*74ce793bSMickaël Salaün } 593*74ce793bSMickaël Salaün 594*74ce793bSMickaël Salaün return inode; 5951da177e4SLinus Torvalds } 5961da177e4SLinus Torvalds 5976c960e68SChristian Brauner static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir, 598549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl) 5991da177e4SLinus Torvalds { 6001da177e4SLinus Torvalds struct inode *inode; 6011da177e4SLinus Torvalds char *name; 602*74ce793bSMickaël Salaün int fd; 6031da177e4SLinus Torvalds 604c5322220SAl Viro name = dentry_name(dentry); 6051da177e4SLinus Torvalds if (name == NULL) 606*74ce793bSMickaël Salaün return -ENOMEM; 6071da177e4SLinus Torvalds 608a718c922SRichard Weinberger fd = file_create(name, mode & 0777); 609*74ce793bSMickaël Salaün if (fd < 0) { 610e9193059SAl Viro __putname(name); 611*74ce793bSMickaël Salaün return fd; 612*74ce793bSMickaël Salaün } 613*74ce793bSMickaël Salaün 614*74ce793bSMickaël Salaün inode = hostfs_iget(dir->i_sb, name); 615*74ce793bSMickaël Salaün __putname(name); 616*74ce793bSMickaël Salaün if (IS_ERR(inode)) 617*74ce793bSMickaël Salaün return PTR_ERR(inode); 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds HOSTFS_I(inode)->fd = fd; 6201da177e4SLinus Torvalds HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE; 6211da177e4SLinus Torvalds d_instantiate(dentry, inode); 622f1adc05eSJeff Dike return 0; 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 6259e443bc3SJames Hogan static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, 62600cd8dd3SAl Viro unsigned int flags) 6271da177e4SLinus Torvalds { 628*74ce793bSMickaël Salaün struct inode *inode = NULL; 6291da177e4SLinus Torvalds char *name; 6301da177e4SLinus Torvalds 631c5322220SAl Viro name = dentry_name(dentry); 632*74ce793bSMickaël Salaün if (name == NULL) 633*74ce793bSMickaël Salaün return ERR_PTR(-ENOMEM); 634*74ce793bSMickaël Salaün 635*74ce793bSMickaël Salaün inode = hostfs_iget(ino->i_sb, name); 636e9193059SAl Viro __putname(name); 637*74ce793bSMickaël Salaün if (IS_ERR(inode)) { 638*74ce793bSMickaël Salaün if (PTR_ERR(inode) == -ENOENT) 639*74ce793bSMickaël Salaün inode = NULL; 640*74ce793bSMickaël Salaün else 641*74ce793bSMickaël Salaün return ERR_CAST(inode); 6421da177e4SLinus Torvalds } 643*74ce793bSMickaël Salaün 64450f30740SAl Viro return d_splice_alias(inode, dentry); 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6479e443bc3SJames Hogan static int hostfs_link(struct dentry *to, struct inode *ino, 6489e443bc3SJames Hogan struct dentry *from) 6491da177e4SLinus Torvalds { 6501da177e4SLinus Torvalds char *from_name, *to_name; 6511da177e4SLinus Torvalds int err; 6521da177e4SLinus Torvalds 653c5322220SAl Viro if ((from_name = dentry_name(from)) == NULL) 654f1adc05eSJeff Dike return -ENOMEM; 655c5322220SAl Viro to_name = dentry_name(to); 6561da177e4SLinus Torvalds if (to_name == NULL) { 657e9193059SAl Viro __putname(from_name); 658f1adc05eSJeff Dike return -ENOMEM; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds err = link_file(to_name, from_name); 661e9193059SAl Viro __putname(from_name); 662e9193059SAl Viro __putname(to_name); 663f1adc05eSJeff Dike return err; 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6669e443bc3SJames Hogan static int hostfs_unlink(struct inode *ino, struct dentry *dentry) 6671da177e4SLinus Torvalds { 6681da177e4SLinus Torvalds char *file; 6691da177e4SLinus Torvalds int err; 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds if (append) 672f1adc05eSJeff Dike return -EPERM; 6731da177e4SLinus Torvalds 674f8d7e187SAl Viro if ((file = dentry_name(dentry)) == NULL) 675f8d7e187SAl Viro return -ENOMEM; 676f8d7e187SAl Viro 6771da177e4SLinus Torvalds err = unlink_file(file); 678e9193059SAl Viro __putname(file); 679f1adc05eSJeff Dike return err; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds 6827a77db95SChristian Brauner static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino, 683549c7297SChristian Brauner struct dentry *dentry, const char *to) 6841da177e4SLinus Torvalds { 6851da177e4SLinus Torvalds char *file; 6861da177e4SLinus Torvalds int err; 6871da177e4SLinus Torvalds 688c5322220SAl Viro if ((file = dentry_name(dentry)) == NULL) 689f1adc05eSJeff Dike return -ENOMEM; 6901da177e4SLinus Torvalds err = make_symlink(file, to); 691e9193059SAl Viro __putname(file); 692f1adc05eSJeff Dike return err; 6931da177e4SLinus Torvalds } 6941da177e4SLinus Torvalds 695c54bd91eSChristian Brauner static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino, 696549c7297SChristian Brauner struct dentry *dentry, umode_t mode) 6971da177e4SLinus Torvalds { 6981da177e4SLinus Torvalds char *file; 6991da177e4SLinus Torvalds int err; 7001da177e4SLinus Torvalds 701c5322220SAl Viro if ((file = dentry_name(dentry)) == NULL) 702f1adc05eSJeff Dike return -ENOMEM; 7031da177e4SLinus Torvalds err = do_mkdir(file, mode); 704e9193059SAl Viro __putname(file); 705f1adc05eSJeff Dike return err; 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds 7089e443bc3SJames Hogan static int hostfs_rmdir(struct inode *ino, struct dentry *dentry) 7091da177e4SLinus Torvalds { 7101da177e4SLinus Torvalds char *file; 7111da177e4SLinus Torvalds int err; 7121da177e4SLinus Torvalds 713c5322220SAl Viro if ((file = dentry_name(dentry)) == NULL) 714f1adc05eSJeff Dike return -ENOMEM; 7156380161cSDominik Brodowski err = hostfs_do_rmdir(file); 716e9193059SAl Viro __putname(file); 717f1adc05eSJeff Dike return err; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds 7205ebb29beSChristian Brauner static int hostfs_mknod(struct mnt_idmap *idmap, struct inode *dir, 721549c7297SChristian Brauner struct dentry *dentry, umode_t mode, dev_t dev) 7221da177e4SLinus Torvalds { 7231da177e4SLinus Torvalds struct inode *inode; 7241da177e4SLinus Torvalds char *name; 7250a370e5dSDavid Howells int err; 7261da177e4SLinus Torvalds 727c5322220SAl Viro name = dentry_name(dentry); 7281da177e4SLinus Torvalds if (name == NULL) 729*74ce793bSMickaël Salaün return -ENOMEM; 7301da177e4SLinus Torvalds 73188f6cd0cSJohannes Stezenbach err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); 732*74ce793bSMickaël Salaün if (err) { 733e9193059SAl Viro __putname(name); 734*74ce793bSMickaël Salaün return err; 735*74ce793bSMickaël Salaün } 736*74ce793bSMickaël Salaün 737*74ce793bSMickaël Salaün inode = hostfs_iget(dir->i_sb, name); 738*74ce793bSMickaël Salaün __putname(name); 739*74ce793bSMickaël Salaün if (IS_ERR(inode)) 740*74ce793bSMickaël Salaün return PTR_ERR(inode); 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds d_instantiate(dentry, inode); 743f1adc05eSJeff Dike return 0; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds 746e18275aeSChristian Brauner static int hostfs_rename2(struct mnt_idmap *idmap, 747549c7297SChristian Brauner struct inode *old_dir, struct dentry *old_dentry, 7489a423bb6SMiklos Szeredi struct inode *new_dir, struct dentry *new_dentry, 7499a423bb6SMiklos Szeredi unsigned int flags) 7501da177e4SLinus Torvalds { 7519a423bb6SMiklos Szeredi char *old_name, *new_name; 7521da177e4SLinus Torvalds int err; 7531da177e4SLinus Torvalds 7549a423bb6SMiklos Szeredi if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) 7559a423bb6SMiklos Szeredi return -EINVAL; 7569a423bb6SMiklos Szeredi 7579a423bb6SMiklos Szeredi old_name = dentry_name(old_dentry); 7589a423bb6SMiklos Szeredi if (old_name == NULL) 759f1adc05eSJeff Dike return -ENOMEM; 7609a423bb6SMiklos Szeredi new_name = dentry_name(new_dentry); 7619a423bb6SMiklos Szeredi if (new_name == NULL) { 7629a423bb6SMiklos Szeredi __putname(old_name); 763f1adc05eSJeff Dike return -ENOMEM; 7641da177e4SLinus Torvalds } 7659a423bb6SMiklos Szeredi if (!flags) 7669a423bb6SMiklos Szeredi err = rename_file(old_name, new_name); 7679a423bb6SMiklos Szeredi else 7689a423bb6SMiklos Szeredi err = rename2_file(old_name, new_name, flags); 7699a423bb6SMiklos Szeredi 7709a423bb6SMiklos Szeredi __putname(old_name); 7719a423bb6SMiklos Szeredi __putname(new_name); 772f1adc05eSJeff Dike return err; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds 7754609e1f1SChristian Brauner static int hostfs_permission(struct mnt_idmap *idmap, 776549c7297SChristian Brauner struct inode *ino, int desired) 7771da177e4SLinus Torvalds { 7781da177e4SLinus Torvalds char *name; 7791da177e4SLinus Torvalds int r = 0, w = 0, x = 0, err; 7801da177e4SLinus Torvalds 78110556cb2SAl Viro if (desired & MAY_NOT_BLOCK) 782b74c79e9SNick Piggin return -ECHILD; 783b74c79e9SNick Piggin 7841da177e4SLinus Torvalds if (desired & MAY_READ) r = 1; 7851da177e4SLinus Torvalds if (desired & MAY_WRITE) w = 1; 7861da177e4SLinus Torvalds if (desired & MAY_EXEC) x = 1; 787c5322220SAl Viro name = inode_name(ino); 788f1adc05eSJeff Dike if (name == NULL) 789f1adc05eSJeff Dike return -ENOMEM; 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) || 7921da177e4SLinus Torvalds S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode)) 7931da177e4SLinus Torvalds err = 0; 7941da177e4SLinus Torvalds else 7951da177e4SLinus Torvalds err = access_file(name, r, w, x); 796e9193059SAl Viro __putname(name); 7971da177e4SLinus Torvalds if (!err) 7984609e1f1SChristian Brauner err = generic_permission(&nop_mnt_idmap, ino, desired); 7991da177e4SLinus Torvalds return err; 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds 802c1632a0fSChristian Brauner static int hostfs_setattr(struct mnt_idmap *idmap, 803549c7297SChristian Brauner struct dentry *dentry, struct iattr *attr) 8041da177e4SLinus Torvalds { 8052b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 8061da177e4SLinus Torvalds struct hostfs_iattr attrs; 8071da177e4SLinus Torvalds char *name; 8081da177e4SLinus Torvalds int err; 8091da177e4SLinus Torvalds 8101025774cSChristoph Hellwig int fd = HOSTFS_I(inode)->fd; 8115822b7faSAlberto Bertogli 812c1632a0fSChristian Brauner err = setattr_prepare(&nop_mnt_idmap, dentry, attr); 8131da177e4SLinus Torvalds if (err) 8141da177e4SLinus Torvalds return err; 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds if (append) 8171da177e4SLinus Torvalds attr->ia_valid &= ~ATTR_SIZE; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds attrs.ia_valid = 0; 8201da177e4SLinus Torvalds if (attr->ia_valid & ATTR_MODE) { 8211da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_MODE; 8221da177e4SLinus Torvalds attrs.ia_mode = attr->ia_mode; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds if (attr->ia_valid & ATTR_UID) { 8251da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_UID; 82629f82ae5SEric W. Biederman attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid); 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds if (attr->ia_valid & ATTR_GID) { 8291da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_GID; 83029f82ae5SEric W. Biederman attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid); 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds if (attr->ia_valid & ATTR_SIZE) { 8331da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_SIZE; 8341da177e4SLinus Torvalds attrs.ia_size = attr->ia_size; 8351da177e4SLinus Torvalds } 8361da177e4SLinus Torvalds if (attr->ia_valid & ATTR_ATIME) { 8371da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_ATIME; 838bca30265SArnd Bergmann attrs.ia_atime = (struct hostfs_timespec) 839bca30265SArnd Bergmann { attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec }; 8401da177e4SLinus Torvalds } 8411da177e4SLinus Torvalds if (attr->ia_valid & ATTR_MTIME) { 8421da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_MTIME; 843bca30265SArnd Bergmann attrs.ia_mtime = (struct hostfs_timespec) 844bca30265SArnd Bergmann { attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec }; 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds if (attr->ia_valid & ATTR_CTIME) { 8471da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_CTIME; 848bca30265SArnd Bergmann attrs.ia_ctime = (struct hostfs_timespec) 849bca30265SArnd Bergmann { attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec }; 8501da177e4SLinus Torvalds } 8511da177e4SLinus Torvalds if (attr->ia_valid & ATTR_ATIME_SET) { 8521da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds if (attr->ia_valid & ATTR_MTIME_SET) { 8551da177e4SLinus Torvalds attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; 8561da177e4SLinus Torvalds } 857c5322220SAl Viro name = dentry_name(dentry); 858f1adc05eSJeff Dike if (name == NULL) 859f1adc05eSJeff Dike return -ENOMEM; 8605822b7faSAlberto Bertogli err = set_attr(name, &attrs, fd); 861e9193059SAl Viro __putname(name); 8621da177e4SLinus Torvalds if (err) 863f1adc05eSJeff Dike return err; 8641da177e4SLinus Torvalds 8651025774cSChristoph Hellwig if ((attr->ia_valid & ATTR_SIZE) && 866bc077320SMarco Stornelli attr->ia_size != i_size_read(inode)) 8673be2be0aSMarco Stornelli truncate_setsize(inode, attr->ia_size); 8681025774cSChristoph Hellwig 869c1632a0fSChristian Brauner setattr_copy(&nop_mnt_idmap, inode, attr); 8701025774cSChristoph Hellwig mark_inode_dirty(inode); 8711025774cSChristoph Hellwig return 0; 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 87492e1d5beSArjan van de Ven static const struct inode_operations hostfs_iops = { 8751da177e4SLinus Torvalds .permission = hostfs_permission, 8761da177e4SLinus Torvalds .setattr = hostfs_setattr, 8771da177e4SLinus Torvalds }; 8781da177e4SLinus Torvalds 87992e1d5beSArjan van de Ven static const struct inode_operations hostfs_dir_iops = { 8801da177e4SLinus Torvalds .create = hostfs_create, 8811da177e4SLinus Torvalds .lookup = hostfs_lookup, 8821da177e4SLinus Torvalds .link = hostfs_link, 8831da177e4SLinus Torvalds .unlink = hostfs_unlink, 8841da177e4SLinus Torvalds .symlink = hostfs_symlink, 8851da177e4SLinus Torvalds .mkdir = hostfs_mkdir, 8861da177e4SLinus Torvalds .rmdir = hostfs_rmdir, 8871da177e4SLinus Torvalds .mknod = hostfs_mknod, 8882773bf00SMiklos Szeredi .rename = hostfs_rename2, 8891da177e4SLinus Torvalds .permission = hostfs_permission, 8901da177e4SLinus Torvalds .setattr = hostfs_setattr, 8911da177e4SLinus Torvalds }; 8921da177e4SLinus Torvalds 8936b255391SAl Viro static const char *hostfs_get_link(struct dentry *dentry, 894fceef393SAl Viro struct inode *inode, 895fceef393SAl Viro struct delayed_call *done) 8961da177e4SLinus Torvalds { 8976b255391SAl Viro char *link; 8986b255391SAl Viro if (!dentry) 8996b255391SAl Viro return ERR_PTR(-ECHILD); 900fceef393SAl Viro link = kmalloc(PATH_MAX, GFP_KERNEL); 901d0352d3eSAl Viro if (link) { 902d0352d3eSAl Viro char *path = dentry_name(dentry); 903d0352d3eSAl Viro int err = -ENOMEM; 904d0352d3eSAl Viro if (path) { 9053b6036d1SAl Viro err = hostfs_do_readlink(path, link, PATH_MAX); 906d0352d3eSAl Viro if (err == PATH_MAX) 9071da177e4SLinus Torvalds err = -E2BIG; 908e9193059SAl Viro __putname(path); 9091da177e4SLinus Torvalds } 910d0352d3eSAl Viro if (err < 0) { 911fceef393SAl Viro kfree(link); 912680baacbSAl Viro return ERR_PTR(err); 913d0352d3eSAl Viro } 914d0352d3eSAl Viro } else { 915680baacbSAl Viro return ERR_PTR(-ENOMEM); 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 918fceef393SAl Viro set_delayed_call(done, kfree_link, link); 919fceef393SAl Viro return link; 920d0352d3eSAl Viro } 921d0352d3eSAl Viro 922d0352d3eSAl Viro static const struct inode_operations hostfs_link_iops = { 9236b255391SAl Viro .get_link = hostfs_get_link, 9241da177e4SLinus Torvalds }; 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) 9271da177e4SLinus Torvalds { 9281da177e4SLinus Torvalds struct inode *root_inode; 92975e8defbSPaolo 'Blaisorblade' Giarrusso char *host_root_path, *req_root = d; 9301da177e4SLinus Torvalds int err; 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds sb->s_blocksize = 1024; 9331da177e4SLinus Torvalds sb->s_blocksize_bits = 10; 9341da177e4SLinus Torvalds sb->s_magic = HOSTFS_SUPER_MAGIC; 9351da177e4SLinus Torvalds sb->s_op = &hostfs_sbops; 936b26d4cd3SAl Viro sb->s_d_op = &simple_dentry_operations; 937752fa51eSWolfgang Illmeyer sb->s_maxbytes = MAX_LFS_FILESIZE; 938ce72750fSSjoerd Simons err = super_setup_bdi(sb); 939ce72750fSSjoerd Simons if (err) 940*74ce793bSMickaël Salaün return err; 9411da177e4SLinus Torvalds 942b58c4e96SAndy Shevchenko /* NULL is printed as '(null)' by printf(): avoid that. */ 94375e8defbSPaolo 'Blaisorblade' Giarrusso if (req_root == NULL) 94475e8defbSPaolo 'Blaisorblade' Giarrusso req_root = ""; 9451da177e4SLinus Torvalds 946601d2c38SAl Viro sb->s_fs_info = host_root_path = 947b58c4e96SAndy Shevchenko kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root); 94875e8defbSPaolo 'Blaisorblade' Giarrusso if (host_root_path == NULL) 949*74ce793bSMickaël Salaün return -ENOMEM; 9501da177e4SLinus Torvalds 951*74ce793bSMickaël Salaün root_inode = hostfs_iget(sb, host_root_path); 952*74ce793bSMickaël Salaün if (IS_ERR(root_inode)) 953*74ce793bSMickaël Salaün return PTR_ERR(root_inode); 95452b209f7SAl Viro 9554754b825SAl Viro if (S_ISLNK(root_inode->i_mode)) { 956*74ce793bSMickaël Salaün char *name; 957*74ce793bSMickaël Salaün 958*74ce793bSMickaël Salaün iput(root_inode); 959*74ce793bSMickaël Salaün name = follow_link(host_root_path); 960*74ce793bSMickaël Salaün if (IS_ERR(name)) 961*74ce793bSMickaël Salaün return PTR_ERR(name); 962*74ce793bSMickaël Salaün 963*74ce793bSMickaël Salaün root_inode = hostfs_iget(sb, name); 96452b209f7SAl Viro kfree(name); 965*74ce793bSMickaël Salaün if (IS_ERR(root_inode)) 966*74ce793bSMickaël Salaün return PTR_ERR(root_inode); 9674754b825SAl Viro } 9681da177e4SLinus Torvalds 96948fde701SAl Viro sb->s_root = d_make_root(root_inode); 9701da177e4SLinus Torvalds if (sb->s_root == NULL) 971*74ce793bSMickaël Salaün return -ENOMEM; 9721da177e4SLinus Torvalds 973f1adc05eSJeff Dike return 0; 9741da177e4SLinus Torvalds } 9751da177e4SLinus Torvalds 9763c26ff6eSAl Viro static struct dentry *hostfs_read_sb(struct file_system_type *type, 9771da177e4SLinus Torvalds int flags, const char *dev_name, 9783c26ff6eSAl Viro void *data) 9791da177e4SLinus Torvalds { 9803c26ff6eSAl Viro return mount_nodev(type, flags, data, hostfs_fill_sb_common); 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds 983601d2c38SAl Viro static void hostfs_kill_sb(struct super_block *s) 984601d2c38SAl Viro { 985601d2c38SAl Viro kill_anon_super(s); 986601d2c38SAl Viro kfree(s->s_fs_info); 987601d2c38SAl Viro } 988601d2c38SAl Viro 9891da177e4SLinus Torvalds static struct file_system_type hostfs_type = { 9901da177e4SLinus Torvalds .owner = THIS_MODULE, 9911da177e4SLinus Torvalds .name = "hostfs", 9923c26ff6eSAl Viro .mount = hostfs_read_sb, 993601d2c38SAl Viro .kill_sb = hostfs_kill_sb, 9941da177e4SLinus Torvalds .fs_flags = 0, 9951da177e4SLinus Torvalds }; 9963e64fe5bSEric W. Biederman MODULE_ALIAS_FS("hostfs"); 9971da177e4SLinus Torvalds 9981da177e4SLinus Torvalds static int __init init_hostfs(void) 9991da177e4SLinus Torvalds { 1000a15f1e41SJohannes Berg hostfs_inode_cache = KMEM_CACHE(hostfs_inode_info, 0); 1001a15f1e41SJohannes Berg if (!hostfs_inode_cache) 1002a15f1e41SJohannes Berg return -ENOMEM; 1003f1adc05eSJeff Dike return register_filesystem(&hostfs_type); 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds static void __exit exit_hostfs(void) 10071da177e4SLinus Torvalds { 10081da177e4SLinus Torvalds unregister_filesystem(&hostfs_type); 1009a15f1e41SJohannes Berg kmem_cache_destroy(hostfs_inode_cache); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds module_init(init_hostfs) 10131da177e4SLinus Torvalds module_exit(exit_hostfs) 10141da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1015