aufs: fix up for the new stable kernel
[pandora-kernel.git] / fs / aufs / procfs.c
1 /*
2  * Copyright (C) 2010-2013 Junjiro R. Okajima
3  *
4  * This program, aufs is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /*
20  * procfs interfaces
21  */
22
23 #include <linux/proc_fs.h>
24 #include "aufs.h"
25
26 static int au_procfs_plm_release(struct inode *inode, struct file *file)
27 {
28         struct au_sbinfo *sbinfo;
29
30         sbinfo = file->private_data;
31         if (sbinfo) {
32                 au_plink_maint_leave(sbinfo);
33                 kobject_put(&sbinfo->si_kobj);
34         }
35
36         return 0;
37 }
38
39 static void au_procfs_plm_write_clean(struct file *file)
40 {
41         struct au_sbinfo *sbinfo;
42
43         sbinfo = file->private_data;
44         if (sbinfo)
45                 au_plink_clean(sbinfo->si_sb, /*verbose*/0);
46 }
47
48 static int au_procfs_plm_write_si(struct file *file, unsigned long id)
49 {
50         int err;
51         struct super_block *sb;
52         struct au_sbinfo *sbinfo;
53
54         err = -EBUSY;
55         if (unlikely(file->private_data))
56                 goto out;
57
58         sb = NULL;
59         /* don't use au_sbilist_lock() here */
60         spin_lock(&au_sbilist.spin);
61         list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
62                 if (id == sysaufs_si_id(sbinfo)) {
63                         kobject_get(&sbinfo->si_kobj);
64                         sb = sbinfo->si_sb;
65                         break;
66                 }
67         spin_unlock(&au_sbilist.spin);
68
69         err = -EINVAL;
70         if (unlikely(!sb))
71                 goto out;
72
73         err = au_plink_maint_enter(sb);
74         if (!err)
75                 /* keep kobject_get() */
76                 file->private_data = sbinfo;
77         else
78                 kobject_put(&sbinfo->si_kobj);
79 out:
80         return err;
81 }
82
83 /*
84  * Accept a valid "si=xxxx" only.
85  * Once it is accepted successfully, accept "clean" too.
86  */
87 static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf,
88                                    size_t count, loff_t *ppos)
89 {
90         ssize_t err;
91         unsigned long id;
92         /* last newline is allowed */
93         char buf[3 + sizeof(unsigned long) * 2 + 1];
94
95         err = -EACCES;
96         if (unlikely(!capable(CAP_SYS_ADMIN)))
97                 goto out;
98
99         err = -EINVAL;
100         if (unlikely(count > sizeof(buf)))
101                 goto out;
102
103         err = copy_from_user(buf, ubuf, count);
104         if (unlikely(err)) {
105                 err = -EFAULT;
106                 goto out;
107         }
108         buf[count] = 0;
109
110         err = -EINVAL;
111         if (!strcmp("clean", buf)) {
112                 au_procfs_plm_write_clean(file);
113                 goto out_success;
114         } else if (unlikely(strncmp("si=", buf, 3)))
115                 goto out;
116
117         err = kstrtoul(buf + 3, 16, &id);
118         if (unlikely(err))
119                 goto out;
120
121         err = au_procfs_plm_write_si(file, id);
122         if (unlikely(err))
123                 goto out;
124
125 out_success:
126         err = count; /* success */
127 out:
128         return err;
129 }
130
131 static const struct file_operations au_procfs_plm_fop = {
132         .write          = au_procfs_plm_write,
133         .release        = au_procfs_plm_release,
134         .owner          = THIS_MODULE
135 };
136
137 /* ---------------------------------------------------------------------- */
138
139 static struct proc_dir_entry *au_procfs_dir;
140
141 void au_procfs_fin(void)
142 {
143         remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir);
144         remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
145 }
146
147 int __init au_procfs_init(void)
148 {
149         int err;
150         struct proc_dir_entry *entry;
151
152         err = -ENOMEM;
153         au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL);
154         if (unlikely(!au_procfs_dir))
155                 goto out;
156
157         entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR,
158                             au_procfs_dir, &au_procfs_plm_fop);
159         if (unlikely(!entry))
160                 goto out_dir;
161
162         err = 0;
163         goto out; /* success */
164
165
166 out_dir:
167         remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
168 out:
169         return err;
170 }