LCOV - code coverage report
Current view: top level - fs/fuse - control.c (source / functions) Hit Total Coverage
Test: Real Lines: 51 150 34.0 %
Date: 2020-10-17 15:46:16 Functions: 0 18 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :   FUSE: Filesystem in Userspace
       3                 :            :   Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
       4                 :            : 
       5                 :            :   This program can be distributed under the terms of the GNU GPL.
       6                 :            :   See the file COPYING.
       7                 :            : */
       8                 :            : 
       9                 :            : #include "fuse_i.h"
      10                 :            : 
      11                 :            : #include <linux/init.h>
      12                 :            : #include <linux/module.h>
      13                 :            : #include <linux/fs_context.h>
      14                 :            : 
      15                 :            : #define FUSE_CTL_SUPER_MAGIC 0x65735543
      16                 :            : 
      17                 :            : /*
      18                 :            :  * This is non-NULL when the single instance of the control filesystem
      19                 :            :  * exists.  Protected by fuse_mutex
      20                 :            :  */
      21                 :            : static struct super_block *fuse_control_sb;
      22                 :            : 
      23                 :          0 : static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
      24                 :            : {
      25                 :            :         struct fuse_conn *fc;
      26                 :          0 :         mutex_lock(&fuse_mutex);
      27                 :          0 :         fc = file_inode(file)->i_private;
      28                 :          0 :         if (fc)
      29                 :          0 :                 fc = fuse_conn_get(fc);
      30                 :          0 :         mutex_unlock(&fuse_mutex);
      31                 :          0 :         return fc;
      32                 :            : }
      33                 :            : 
      34                 :          0 : static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
      35                 :            :                                      size_t count, loff_t *ppos)
      36                 :            : {
      37                 :          0 :         struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
      38                 :          0 :         if (fc) {
      39                 :          0 :                 if (fc->abort_err)
      40                 :          0 :                         fc->aborted = true;
      41                 :          0 :                 fuse_abort_conn(fc);
      42                 :          0 :                 fuse_conn_put(fc);
      43                 :            :         }
      44                 :          0 :         return count;
      45                 :            : }
      46                 :            : 
      47                 :          0 : static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
      48                 :            :                                       size_t len, loff_t *ppos)
      49                 :            : {
      50                 :            :         char tmp[32];
      51                 :            :         size_t size;
      52                 :            : 
      53                 :          0 :         if (!*ppos) {
      54                 :            :                 long value;
      55                 :          0 :                 struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
      56                 :          0 :                 if (!fc)
      57                 :            :                         return 0;
      58                 :            : 
      59                 :          0 :                 value = atomic_read(&fc->num_waiting);
      60                 :          0 :                 file->private_data = (void *)value;
      61                 :          0 :                 fuse_conn_put(fc);
      62                 :            :         }
      63                 :          0 :         size = sprintf(tmp, "%ld\n", (long)file->private_data);
      64                 :          0 :         return simple_read_from_buffer(buf, len, ppos, tmp, size);
      65                 :            : }
      66                 :            : 
      67                 :          0 : static ssize_t fuse_conn_limit_read(struct file *file, char __user *buf,
      68                 :            :                                     size_t len, loff_t *ppos, unsigned val)
      69                 :            : {
      70                 :            :         char tmp[32];
      71                 :          0 :         size_t size = sprintf(tmp, "%u\n", val);
      72                 :            : 
      73                 :          0 :         return simple_read_from_buffer(buf, len, ppos, tmp, size);
      74                 :            : }
      75                 :            : 
      76                 :          0 : static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf,
      77                 :            :                                      size_t count, loff_t *ppos, unsigned *val,
      78                 :            :                                      unsigned global_limit)
      79                 :            : {
      80                 :            :         unsigned long t;
      81                 :            :         unsigned limit = (1 << 16) - 1;
      82                 :            :         int err;
      83                 :            : 
      84                 :          0 :         if (*ppos)
      85                 :            :                 return -EINVAL;
      86                 :            : 
      87                 :          0 :         err = kstrtoul_from_user(buf, count, 0, &t);
      88                 :          0 :         if (err)
      89                 :            :                 return err;
      90                 :            : 
      91                 :          0 :         if (!capable(CAP_SYS_ADMIN))
      92                 :          0 :                 limit = min(limit, global_limit);
      93                 :            : 
      94                 :          0 :         if (t > limit)
      95                 :            :                 return -EINVAL;
      96                 :            : 
      97                 :          0 :         *val = t;
      98                 :            : 
      99                 :          0 :         return count;
     100                 :            : }
     101                 :            : 
     102                 :          0 : static ssize_t fuse_conn_max_background_read(struct file *file,
     103                 :            :                                              char __user *buf, size_t len,
     104                 :            :                                              loff_t *ppos)
     105                 :            : {
     106                 :            :         struct fuse_conn *fc;
     107                 :            :         unsigned val;
     108                 :            : 
     109                 :          0 :         fc = fuse_ctl_file_conn_get(file);
     110                 :          0 :         if (!fc)
     111                 :            :                 return 0;
     112                 :            : 
     113                 :            :         val = READ_ONCE(fc->max_background);
     114                 :          0 :         fuse_conn_put(fc);
     115                 :            : 
     116                 :          0 :         return fuse_conn_limit_read(file, buf, len, ppos, val);
     117                 :            : }
     118                 :            : 
     119                 :          0 : static ssize_t fuse_conn_max_background_write(struct file *file,
     120                 :            :                                               const char __user *buf,
     121                 :            :                                               size_t count, loff_t *ppos)
     122                 :            : {
     123                 :            :         unsigned uninitialized_var(val);
     124                 :            :         ssize_t ret;
     125                 :            : 
     126                 :          0 :         ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
     127                 :            :                                     max_user_bgreq);
     128                 :          0 :         if (ret > 0) {
     129                 :          0 :                 struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
     130                 :          0 :                 if (fc) {
     131                 :            :                         spin_lock(&fc->bg_lock);
     132                 :          0 :                         fc->max_background = val;
     133                 :          0 :                         fc->blocked = fc->num_background >= fc->max_background;
     134                 :          0 :                         if (!fc->blocked)
     135                 :          0 :                                 wake_up(&fc->blocked_waitq);
     136                 :            :                         spin_unlock(&fc->bg_lock);
     137                 :          0 :                         fuse_conn_put(fc);
     138                 :            :                 }
     139                 :            :         }
     140                 :            : 
     141                 :          0 :         return ret;
     142                 :            : }
     143                 :            : 
     144                 :          0 : static ssize_t fuse_conn_congestion_threshold_read(struct file *file,
     145                 :            :                                                    char __user *buf, size_t len,
     146                 :            :                                                    loff_t *ppos)
     147                 :            : {
     148                 :            :         struct fuse_conn *fc;
     149                 :            :         unsigned val;
     150                 :            : 
     151                 :          0 :         fc = fuse_ctl_file_conn_get(file);
     152                 :          0 :         if (!fc)
     153                 :            :                 return 0;
     154                 :            : 
     155                 :            :         val = READ_ONCE(fc->congestion_threshold);
     156                 :          0 :         fuse_conn_put(fc);
     157                 :            : 
     158                 :          0 :         return fuse_conn_limit_read(file, buf, len, ppos, val);
     159                 :            : }
     160                 :            : 
     161                 :          0 : static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
     162                 :            :                                                     const char __user *buf,
     163                 :            :                                                     size_t count, loff_t *ppos)
     164                 :            : {
     165                 :            :         unsigned uninitialized_var(val);
     166                 :            :         struct fuse_conn *fc;
     167                 :            :         ssize_t ret;
     168                 :            : 
     169                 :          0 :         ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
     170                 :            :                                     max_user_congthresh);
     171                 :          0 :         if (ret <= 0)
     172                 :            :                 goto out;
     173                 :          0 :         fc = fuse_ctl_file_conn_get(file);
     174                 :          0 :         if (!fc)
     175                 :            :                 goto out;
     176                 :            : 
     177                 :            :         spin_lock(&fc->bg_lock);
     178                 :          0 :         fc->congestion_threshold = val;
     179                 :          0 :         if (fc->sb) {
     180                 :          0 :                 if (fc->num_background < fc->congestion_threshold) {
     181                 :          0 :                         clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
     182                 :          0 :                         clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
     183                 :            :                 } else {
     184                 :          0 :                         set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
     185                 :          0 :                         set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
     186                 :            :                 }
     187                 :            :         }
     188                 :            :         spin_unlock(&fc->bg_lock);
     189                 :          0 :         fuse_conn_put(fc);
     190                 :            : out:
     191                 :          0 :         return ret;
     192                 :            : }
     193                 :            : 
     194                 :            : static const struct file_operations fuse_ctl_abort_ops = {
     195                 :            :         .open = nonseekable_open,
     196                 :            :         .write = fuse_conn_abort_write,
     197                 :            :         .llseek = no_llseek,
     198                 :            : };
     199                 :            : 
     200                 :            : static const struct file_operations fuse_ctl_waiting_ops = {
     201                 :            :         .open = nonseekable_open,
     202                 :            :         .read = fuse_conn_waiting_read,
     203                 :            :         .llseek = no_llseek,
     204                 :            : };
     205                 :            : 
     206                 :            : static const struct file_operations fuse_conn_max_background_ops = {
     207                 :            :         .open = nonseekable_open,
     208                 :            :         .read = fuse_conn_max_background_read,
     209                 :            :         .write = fuse_conn_max_background_write,
     210                 :            :         .llseek = no_llseek,
     211                 :            : };
     212                 :            : 
     213                 :            : static const struct file_operations fuse_conn_congestion_threshold_ops = {
     214                 :            :         .open = nonseekable_open,
     215                 :            :         .read = fuse_conn_congestion_threshold_read,
     216                 :            :         .write = fuse_conn_congestion_threshold_write,
     217                 :            :         .llseek = no_llseek,
     218                 :            : };
     219                 :            : 
     220                 :          3 : static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
     221                 :            :                                           struct fuse_conn *fc,
     222                 :            :                                           const char *name,
     223                 :            :                                           int mode, int nlink,
     224                 :            :                                           const struct inode_operations *iop,
     225                 :            :                                           const struct file_operations *fop)
     226                 :            : {
     227                 :            :         struct dentry *dentry;
     228                 :            :         struct inode *inode;
     229                 :            : 
     230                 :          3 :         BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES);
     231                 :          3 :         dentry = d_alloc_name(parent, name);
     232                 :          3 :         if (!dentry)
     233                 :            :                 return NULL;
     234                 :            : 
     235                 :          3 :         inode = new_inode(fuse_control_sb);
     236                 :          3 :         if (!inode) {
     237                 :          0 :                 dput(dentry);
     238                 :          0 :                 return NULL;
     239                 :            :         }
     240                 :            : 
     241                 :          3 :         inode->i_ino = get_next_ino();
     242                 :          3 :         inode->i_mode = mode;
     243                 :          3 :         inode->i_uid = fc->user_id;
     244                 :          3 :         inode->i_gid = fc->group_id;
     245                 :          3 :         inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
     246                 :            :         /* setting ->i_op to NULL is not allowed */
     247                 :          3 :         if (iop)
     248                 :          3 :                 inode->i_op = iop;
     249                 :          3 :         inode->i_fop = fop;
     250                 :          3 :         set_nlink(inode, nlink);
     251                 :          3 :         inode->i_private = fc;
     252                 :          3 :         d_add(dentry, inode);
     253                 :            : 
     254                 :          3 :         fc->ctl_dentry[fc->ctl_ndents++] = dentry;
     255                 :            : 
     256                 :          3 :         return dentry;
     257                 :            : }
     258                 :            : 
     259                 :            : /*
     260                 :            :  * Add a connection to the control filesystem (if it exists).  Caller
     261                 :            :  * must hold fuse_mutex
     262                 :            :  */
     263                 :          3 : int fuse_ctl_add_conn(struct fuse_conn *fc)
     264                 :            : {
     265                 :            :         struct dentry *parent;
     266                 :            :         char name[32];
     267                 :            : 
     268                 :          3 :         if (!fuse_control_sb)
     269                 :            :                 return 0;
     270                 :            : 
     271                 :          3 :         parent = fuse_control_sb->s_root;
     272                 :          3 :         inc_nlink(d_inode(parent));
     273                 :          3 :         sprintf(name, "%u", fc->dev);
     274                 :          3 :         parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
     275                 :            :                                      &simple_dir_inode_operations,
     276                 :            :                                      &simple_dir_operations);
     277                 :          3 :         if (!parent)
     278                 :            :                 goto err;
     279                 :            : 
     280                 :          3 :         if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1,
     281                 :          3 :                                  NULL, &fuse_ctl_waiting_ops) ||
     282                 :          3 :             !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1,
     283                 :          3 :                                  NULL, &fuse_ctl_abort_ops) ||
     284                 :          3 :             !fuse_ctl_add_dentry(parent, fc, "max_background", S_IFREG | 0600,
     285                 :          3 :                                  1, NULL, &fuse_conn_max_background_ops) ||
     286                 :          3 :             !fuse_ctl_add_dentry(parent, fc, "congestion_threshold",
     287                 :            :                                  S_IFREG | 0600, 1, NULL,
     288                 :            :                                  &fuse_conn_congestion_threshold_ops))
     289                 :            :                 goto err;
     290                 :            : 
     291                 :            :         return 0;
     292                 :            : 
     293                 :            :  err:
     294                 :          0 :         fuse_ctl_remove_conn(fc);
     295                 :          0 :         return -ENOMEM;
     296                 :            : }
     297                 :            : 
     298                 :            : /*
     299                 :            :  * Remove a connection from the control filesystem (if it exists).
     300                 :            :  * Caller must hold fuse_mutex
     301                 :            :  */
     302                 :          0 : void fuse_ctl_remove_conn(struct fuse_conn *fc)
     303                 :            : {
     304                 :            :         int i;
     305                 :            : 
     306                 :          0 :         if (!fuse_control_sb)
     307                 :          0 :                 return;
     308                 :            : 
     309                 :          0 :         for (i = fc->ctl_ndents - 1; i >= 0; i--) {
     310                 :          0 :                 struct dentry *dentry = fc->ctl_dentry[i];
     311                 :          0 :                 d_inode(dentry)->i_private = NULL;
     312                 :          0 :                 if (!i) {
     313                 :            :                         /* Get rid of submounts: */
     314                 :          0 :                         d_invalidate(dentry);
     315                 :            :                 }
     316                 :          0 :                 dput(dentry);
     317                 :            :         }
     318                 :          0 :         drop_nlink(d_inode(fuse_control_sb->s_root));
     319                 :            : }
     320                 :            : 
     321                 :          3 : static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx)
     322                 :            : {
     323                 :            :         static const struct tree_descr empty_descr = {""};
     324                 :            :         struct fuse_conn *fc;
     325                 :            :         int err;
     326                 :            : 
     327                 :          3 :         err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr);
     328                 :          3 :         if (err)
     329                 :            :                 return err;
     330                 :            : 
     331                 :          3 :         mutex_lock(&fuse_mutex);
     332                 :          3 :         BUG_ON(fuse_control_sb);
     333                 :          3 :         fuse_control_sb = sb;
     334                 :          3 :         list_for_each_entry(fc, &fuse_conn_list, entry) {
     335                 :          3 :                 err = fuse_ctl_add_conn(fc);
     336                 :          3 :                 if (err) {
     337                 :          0 :                         fuse_control_sb = NULL;
     338                 :          0 :                         mutex_unlock(&fuse_mutex);
     339                 :          0 :                         return err;
     340                 :            :                 }
     341                 :            :         }
     342                 :          3 :         mutex_unlock(&fuse_mutex);
     343                 :            : 
     344                 :          3 :         return 0;
     345                 :            : }
     346                 :            : 
     347                 :          3 : static int fuse_ctl_get_tree(struct fs_context *fc)
     348                 :            : {
     349                 :          3 :         return get_tree_single(fc, fuse_ctl_fill_super);
     350                 :            : }
     351                 :            : 
     352                 :            : static const struct fs_context_operations fuse_ctl_context_ops = {
     353                 :            :         .get_tree       = fuse_ctl_get_tree,
     354                 :            : };
     355                 :            : 
     356                 :          3 : static int fuse_ctl_init_fs_context(struct fs_context *fc)
     357                 :            : {
     358                 :          3 :         fc->ops = &fuse_ctl_context_ops;
     359                 :          3 :         return 0;
     360                 :            : }
     361                 :            : 
     362                 :          0 : static void fuse_ctl_kill_sb(struct super_block *sb)
     363                 :            : {
     364                 :            :         struct fuse_conn *fc;
     365                 :            : 
     366                 :          0 :         mutex_lock(&fuse_mutex);
     367                 :          0 :         fuse_control_sb = NULL;
     368                 :          0 :         list_for_each_entry(fc, &fuse_conn_list, entry)
     369                 :          0 :                 fc->ctl_ndents = 0;
     370                 :          0 :         mutex_unlock(&fuse_mutex);
     371                 :            : 
     372                 :          0 :         kill_litter_super(sb);
     373                 :          0 : }
     374                 :            : 
     375                 :            : static struct file_system_type fuse_ctl_fs_type = {
     376                 :            :         .owner          = THIS_MODULE,
     377                 :            :         .name           = "fusectl",
     378                 :            :         .init_fs_context = fuse_ctl_init_fs_context,
     379                 :            :         .kill_sb        = fuse_ctl_kill_sb,
     380                 :            : };
     381                 :            : MODULE_ALIAS_FS("fusectl");
     382                 :            : 
     383                 :          3 : int __init fuse_ctl_init(void)
     384                 :            : {
     385                 :          3 :         return register_filesystem(&fuse_ctl_fs_type);
     386                 :            : }
     387                 :            : 
     388                 :          0 : void __exit fuse_ctl_cleanup(void)
     389                 :            : {
     390                 :          0 :         unregister_filesystem(&fuse_ctl_fs_type);
     391                 :          0 : }
    

Generated by: LCOV version 1.14