Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
0005  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/errno.h>
0011 #include <linux/fs.h>
0012 #include <linux/file.h>
0013 #include <linux/stat.h>
0014 #include <linux/string.h>
0015 #include <linux/inet.h>
0016 #include <linux/pagemap.h>
0017 #include <linux/mount.h>
0018 #include <linux/idr.h>
0019 #include <linux/sched.h>
0020 #include <linux/slab.h>
0021 #include <linux/statfs.h>
0022 #include <linux/magic.h>
0023 #include <linux/fscache.h>
0024 #include <net/9p/9p.h>
0025 #include <net/9p/client.h>
0026 
0027 #include "v9fs.h"
0028 #include "v9fs_vfs.h"
0029 #include "fid.h"
0030 #include "xattr.h"
0031 #include "acl.h"
0032 
0033 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
0034 
0035 /**
0036  * v9fs_set_super - set the superblock
0037  * @s: super block
0038  * @data: file system specific data
0039  *
0040  */
0041 
0042 static int v9fs_set_super(struct super_block *s, void *data)
0043 {
0044     s->s_fs_info = data;
0045     return set_anon_super(s, data);
0046 }
0047 
0048 /**
0049  * v9fs_fill_super - populate superblock with info
0050  * @sb: superblock
0051  * @v9ses: session information
0052  * @flags: flags propagated from v9fs_mount()
0053  *
0054  */
0055 
0056 static int
0057 v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
0058         int flags)
0059 {
0060     int ret;
0061 
0062     sb->s_maxbytes = MAX_LFS_FILESIZE;
0063     sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
0064     sb->s_blocksize = 1 << sb->s_blocksize_bits;
0065     sb->s_magic = V9FS_MAGIC;
0066     if (v9fs_proto_dotl(v9ses)) {
0067         sb->s_op = &v9fs_super_ops_dotl;
0068         sb->s_xattr = v9fs_xattr_handlers;
0069     } else {
0070         sb->s_op = &v9fs_super_ops;
0071         sb->s_time_max = U32_MAX;
0072     }
0073 
0074     sb->s_time_min = 0;
0075 
0076     ret = super_setup_bdi(sb);
0077     if (ret)
0078         return ret;
0079 
0080     if (!v9ses->cache) {
0081         sb->s_bdi->ra_pages = 0;
0082         sb->s_bdi->io_pages = 0;
0083     } else {
0084         sb->s_bdi->ra_pages = v9ses->maxdata >> PAGE_SHIFT;
0085         sb->s_bdi->io_pages = v9ses->maxdata >> PAGE_SHIFT;
0086     }
0087 
0088     sb->s_flags |= SB_ACTIVE | SB_DIRSYNC;
0089     if (!v9ses->cache)
0090         sb->s_flags |= SB_SYNCHRONOUS;
0091 
0092 #ifdef CONFIG_9P_FS_POSIX_ACL
0093     if ((v9ses->flags & V9FS_ACL_MASK) == V9FS_POSIX_ACL)
0094         sb->s_flags |= SB_POSIXACL;
0095 #endif
0096 
0097     return 0;
0098 }
0099 
0100 /**
0101  * v9fs_mount - mount a superblock
0102  * @fs_type: file system type
0103  * @flags: mount flags
0104  * @dev_name: device name that was mounted
0105  * @data: mount options
0106  *
0107  */
0108 
0109 static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
0110                const char *dev_name, void *data)
0111 {
0112     struct super_block *sb = NULL;
0113     struct inode *inode = NULL;
0114     struct dentry *root = NULL;
0115     struct v9fs_session_info *v9ses = NULL;
0116     umode_t mode = 0777 | S_ISVTX;
0117     struct p9_fid *fid;
0118     int retval = 0;
0119 
0120     p9_debug(P9_DEBUG_VFS, "\n");
0121 
0122     v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
0123     if (!v9ses)
0124         return ERR_PTR(-ENOMEM);
0125 
0126     fid = v9fs_session_init(v9ses, dev_name, data);
0127     if (IS_ERR(fid)) {
0128         retval = PTR_ERR(fid);
0129         goto free_session;
0130     }
0131 
0132     sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses);
0133     if (IS_ERR(sb)) {
0134         retval = PTR_ERR(sb);
0135         goto clunk_fid;
0136     }
0137     retval = v9fs_fill_super(sb, v9ses, flags);
0138     if (retval)
0139         goto release_sb;
0140 
0141     if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
0142         sb->s_d_op = &v9fs_cached_dentry_operations;
0143     else
0144         sb->s_d_op = &v9fs_dentry_operations;
0145 
0146     inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
0147     if (IS_ERR(inode)) {
0148         retval = PTR_ERR(inode);
0149         goto release_sb;
0150     }
0151 
0152     root = d_make_root(inode);
0153     if (!root) {
0154         retval = -ENOMEM;
0155         goto release_sb;
0156     }
0157     sb->s_root = root;
0158     if (v9fs_proto_dotl(v9ses)) {
0159         struct p9_stat_dotl *st = NULL;
0160 
0161         st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
0162         if (IS_ERR(st)) {
0163             retval = PTR_ERR(st);
0164             goto release_sb;
0165         }
0166         d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
0167         v9fs_stat2inode_dotl(st, d_inode(root), 0);
0168         kfree(st);
0169     } else {
0170         struct p9_wstat *st = NULL;
0171 
0172         st = p9_client_stat(fid);
0173         if (IS_ERR(st)) {
0174             retval = PTR_ERR(st);
0175             goto release_sb;
0176         }
0177 
0178         d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
0179         v9fs_stat2inode(st, d_inode(root), sb, 0);
0180 
0181         p9stat_free(st);
0182         kfree(st);
0183     }
0184     retval = v9fs_get_acl(inode, fid);
0185     if (retval)
0186         goto release_sb;
0187     v9fs_fid_add(root, &fid);
0188 
0189     p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n");
0190     return dget(sb->s_root);
0191 
0192 clunk_fid:
0193     p9_fid_put(fid);
0194     v9fs_session_close(v9ses);
0195 free_session:
0196     kfree(v9ses);
0197     return ERR_PTR(retval);
0198 
0199 release_sb:
0200     /*
0201      * we will do the session_close and root dentry release
0202      * in the below call. But we need to clunk fid, because we haven't
0203      * attached the fid to dentry so it won't get clunked
0204      * automatically.
0205      */
0206     p9_fid_put(fid);
0207     deactivate_locked_super(sb);
0208     return ERR_PTR(retval);
0209 }
0210 
0211 /**
0212  * v9fs_kill_super - Kill Superblock
0213  * @s: superblock
0214  *
0215  */
0216 
0217 static void v9fs_kill_super(struct super_block *s)
0218 {
0219     struct v9fs_session_info *v9ses = s->s_fs_info;
0220 
0221     p9_debug(P9_DEBUG_VFS, " %p\n", s);
0222 
0223     kill_anon_super(s);
0224 
0225     v9fs_session_cancel(v9ses);
0226     v9fs_session_close(v9ses);
0227     kfree(v9ses);
0228     s->s_fs_info = NULL;
0229     p9_debug(P9_DEBUG_VFS, "exiting kill_super\n");
0230 }
0231 
0232 static void
0233 v9fs_umount_begin(struct super_block *sb)
0234 {
0235     struct v9fs_session_info *v9ses;
0236 
0237     v9ses = sb->s_fs_info;
0238     v9fs_session_begin_cancel(v9ses);
0239 }
0240 
0241 static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
0242 {
0243     struct v9fs_session_info *v9ses;
0244     struct p9_fid *fid;
0245     struct p9_rstatfs rs;
0246     int res;
0247 
0248     fid = v9fs_fid_lookup(dentry);
0249     if (IS_ERR(fid)) {
0250         res = PTR_ERR(fid);
0251         goto done;
0252     }
0253 
0254     v9ses = v9fs_dentry2v9ses(dentry);
0255     if (v9fs_proto_dotl(v9ses)) {
0256         res = p9_client_statfs(fid, &rs);
0257         if (res == 0) {
0258             buf->f_type = rs.type;
0259             buf->f_bsize = rs.bsize;
0260             buf->f_blocks = rs.blocks;
0261             buf->f_bfree = rs.bfree;
0262             buf->f_bavail = rs.bavail;
0263             buf->f_files = rs.files;
0264             buf->f_ffree = rs.ffree;
0265             buf->f_fsid = u64_to_fsid(rs.fsid);
0266             buf->f_namelen = rs.namelen;
0267         }
0268         if (res != -ENOSYS)
0269             goto done;
0270     }
0271     res = simple_statfs(dentry, buf);
0272 done:
0273     p9_fid_put(fid);
0274     return res;
0275 }
0276 
0277 static int v9fs_drop_inode(struct inode *inode)
0278 {
0279     struct v9fs_session_info *v9ses;
0280 
0281     v9ses = v9fs_inode2v9ses(inode);
0282     if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
0283         return generic_drop_inode(inode);
0284     /*
0285      * in case of non cached mode always drop the
0286      * inode because we want the inode attribute
0287      * to always match that on the server.
0288      */
0289     return 1;
0290 }
0291 
0292 static int v9fs_write_inode(struct inode *inode,
0293                 struct writeback_control *wbc)
0294 {
0295     int ret;
0296     struct p9_wstat wstat;
0297     struct v9fs_inode *v9inode;
0298     /*
0299      * send an fsync request to server irrespective of
0300      * wbc->sync_mode.
0301      */
0302     p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
0303     v9inode = V9FS_I(inode);
0304     if (!v9inode->writeback_fid)
0305         return 0;
0306     v9fs_blank_wstat(&wstat);
0307 
0308     ret = p9_client_wstat(v9inode->writeback_fid, &wstat);
0309     if (ret < 0) {
0310         __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
0311         return ret;
0312     }
0313     fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode));
0314     return 0;
0315 }
0316 
0317 static int v9fs_write_inode_dotl(struct inode *inode,
0318                  struct writeback_control *wbc)
0319 {
0320     int ret;
0321     struct v9fs_inode *v9inode;
0322     /*
0323      * send an fsync request to server irrespective of
0324      * wbc->sync_mode.
0325      */
0326     v9inode = V9FS_I(inode);
0327     p9_debug(P9_DEBUG_VFS, "%s: inode %p, writeback_fid %p\n",
0328          __func__, inode, v9inode->writeback_fid);
0329     if (!v9inode->writeback_fid)
0330         return 0;
0331 
0332     ret = p9_client_fsync(v9inode->writeback_fid, 0);
0333     if (ret < 0) {
0334         __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
0335         return ret;
0336     }
0337     fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode));
0338     return 0;
0339 }
0340 
0341 static const struct super_operations v9fs_super_ops = {
0342     .alloc_inode = v9fs_alloc_inode,
0343     .free_inode = v9fs_free_inode,
0344     .statfs = simple_statfs,
0345     .evict_inode = v9fs_evict_inode,
0346     .show_options = v9fs_show_options,
0347     .umount_begin = v9fs_umount_begin,
0348     .write_inode = v9fs_write_inode,
0349 };
0350 
0351 static const struct super_operations v9fs_super_ops_dotl = {
0352     .alloc_inode = v9fs_alloc_inode,
0353     .free_inode = v9fs_free_inode,
0354     .statfs = v9fs_statfs,
0355     .drop_inode = v9fs_drop_inode,
0356     .evict_inode = v9fs_evict_inode,
0357     .show_options = v9fs_show_options,
0358     .umount_begin = v9fs_umount_begin,
0359     .write_inode = v9fs_write_inode_dotl,
0360 };
0361 
0362 struct file_system_type v9fs_fs_type = {
0363     .name = "9p",
0364     .mount = v9fs_mount,
0365     .kill_sb = v9fs_kill_super,
0366     .owner = THIS_MODULE,
0367     .fs_flags = FS_RENAME_DOES_D_MOVE,
0368 };
0369 MODULE_ALIAS_FS("9p");