linux/fs/ecryptfs/kthread.c
<<
>>
Prefs
   1/**
   2 * eCryptfs: Linux filesystem encryption layer
   3 *
   4 * Copyright (C) 2008 International Business Machines Corp.
   5 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of the
  10 * License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  20 * 02111-1307, USA.
  21 */
  22
  23#include <linux/kthread.h>
  24#include <linux/freezer.h>
  25#include <linux/slab.h>
  26#include <linux/wait.h>
  27#include <linux/mount.h>
  28#include "ecryptfs_kernel.h"
  29
  30struct ecryptfs_open_req {
  31        struct file **lower_file;
  32        struct path path;
  33        struct completion done;
  34        struct list_head kthread_ctl_list;
  35};
  36
  37static struct ecryptfs_kthread_ctl {
  38#define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001
  39        u32 flags;
  40        struct mutex mux;
  41        struct list_head req_list;
  42        wait_queue_head_t wait;
  43} ecryptfs_kthread_ctl;
  44
  45static struct task_struct *ecryptfs_kthread;
  46
  47/**
  48 * ecryptfs_threadfn
  49 * @ignored: ignored
  50 *
  51 * The eCryptfs kernel thread that has the responsibility of getting
  52 * the lower file with RW permissions.
  53 *
  54 * Returns zero on success; non-zero otherwise
  55 */
  56static int ecryptfs_threadfn(void *ignored)
  57{
  58        set_freezable();
  59        while (1)  {
  60                struct ecryptfs_open_req *req;
  61
  62                wait_event_freezable(
  63                        ecryptfs_kthread_ctl.wait,
  64                        (!list_empty(&ecryptfs_kthread_ctl.req_list)
  65                         || kthread_should_stop()));
  66                mutex_lock(&ecryptfs_kthread_ctl.mux);
  67                if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
  68                        mutex_unlock(&ecryptfs_kthread_ctl.mux);
  69                        goto out;
  70                }
  71                while (!list_empty(&ecryptfs_kthread_ctl.req_list)) {
  72                        req = list_first_entry(&ecryptfs_kthread_ctl.req_list,
  73                                               struct ecryptfs_open_req,
  74                                               kthread_ctl_list);
  75                        list_del(&req->kthread_ctl_list);
  76                        *req->lower_file = dentry_open(&req->path,
  77                                (O_RDWR | O_LARGEFILE), current_cred());
  78                        complete(&req->done);
  79                }
  80                mutex_unlock(&ecryptfs_kthread_ctl.mux);
  81        }
  82out:
  83        return 0;
  84}
  85
  86int __init ecryptfs_init_kthread(void)
  87{
  88        int rc = 0;
  89
  90        mutex_init(&ecryptfs_kthread_ctl.mux);
  91        init_waitqueue_head(&ecryptfs_kthread_ctl.wait);
  92        INIT_LIST_HEAD(&ecryptfs_kthread_ctl.req_list);
  93        ecryptfs_kthread = kthread_run(&ecryptfs_threadfn, NULL,
  94                                       "ecryptfs-kthread");
  95        if (IS_ERR(ecryptfs_kthread)) {
  96                rc = PTR_ERR(ecryptfs_kthread);
  97                printk(KERN_ERR "%s: Failed to create kernel thread; rc = [%d]"
  98                       "\n", __func__, rc);
  99        }
 100        return rc;
 101}
 102
 103void ecryptfs_destroy_kthread(void)
 104{
 105        struct ecryptfs_open_req *req, *tmp;
 106
 107        mutex_lock(&ecryptfs_kthread_ctl.mux);
 108        ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;
 109        list_for_each_entry_safe(req, tmp, &ecryptfs_kthread_ctl.req_list,
 110                                 kthread_ctl_list) {
 111                list_del(&req->kthread_ctl_list);
 112                *req->lower_file = ERR_PTR(-EIO);
 113                complete(&req->done);
 114        }
 115        mutex_unlock(&ecryptfs_kthread_ctl.mux);
 116        kthread_stop(ecryptfs_kthread);
 117        wake_up(&ecryptfs_kthread_ctl.wait);
 118}
 119
 120/**
 121 * ecryptfs_privileged_open
 122 * @lower_file: Result of dentry_open by root on lower dentry
 123 * @lower_dentry: Lower dentry for file to open
 124 * @lower_mnt: Lower vfsmount for file to open
 125 *
 126 * This function gets a r/w file opened againt the lower dentry.
 127 *
 128 * Returns zero on success; non-zero otherwise
 129 */
 130int ecryptfs_privileged_open(struct file **lower_file,
 131                             struct dentry *lower_dentry,
 132                             struct vfsmount *lower_mnt,
 133                             const struct cred *cred)
 134{
 135        struct ecryptfs_open_req req;
 136        int flags = O_LARGEFILE;
 137        int rc = 0;
 138
 139        init_completion(&req.done);
 140        req.lower_file = lower_file;
 141        req.path.dentry = lower_dentry;
 142        req.path.mnt = lower_mnt;
 143
 144        /* Corresponding dput() and mntput() are done when the
 145         * lower file is fput() when all eCryptfs files for the inode are
 146         * released. */
 147        flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
 148        (*lower_file) = dentry_open(&req.path, flags, cred);
 149        if (!IS_ERR(*lower_file))
 150                goto out;
 151        if ((flags & O_ACCMODE) == O_RDONLY) {
 152                rc = PTR_ERR((*lower_file));
 153                goto out;
 154        }
 155        mutex_lock(&ecryptfs_kthread_ctl.mux);
 156        if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
 157                rc = -EIO;
 158                mutex_unlock(&ecryptfs_kthread_ctl.mux);
 159                printk(KERN_ERR "%s: We are in the middle of shutting down; "
 160                       "aborting privileged request to open lower file\n",
 161                        __func__);
 162                goto out;
 163        }
 164        list_add_tail(&req.kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
 165        mutex_unlock(&ecryptfs_kthread_ctl.mux);
 166        wake_up(&ecryptfs_kthread_ctl.wait);
 167        wait_for_completion(&req.done);
 168        if (IS_ERR(*lower_file))
 169                rc = PTR_ERR(*lower_file);
 170out:
 171        return rc;
 172}
 173