]>
Commit | Line | Data |
---|---|---|
e14748e8 SF |
1 | /* |
2 | * Copyright (C) 2010-2016 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, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | /* | |
19 | * procfs interfaces | |
20 | */ | |
21 | ||
22 | #include <linux/proc_fs.h> | |
23 | #include "aufs.h" | |
24 | ||
25 | static int au_procfs_plm_release(struct inode *inode, struct file *file) | |
26 | { | |
27 | struct au_sbinfo *sbinfo; | |
28 | ||
29 | sbinfo = file->private_data; | |
30 | if (sbinfo) { | |
31 | au_plink_maint_leave(sbinfo); | |
32 | kobject_put(&sbinfo->si_kobj); | |
33 | } | |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
38 | static void au_procfs_plm_write_clean(struct file *file) | |
39 | { | |
40 | struct au_sbinfo *sbinfo; | |
41 | ||
42 | sbinfo = file->private_data; | |
43 | if (sbinfo) | |
44 | au_plink_clean(sbinfo->si_sb, /*verbose*/0); | |
45 | } | |
46 | ||
47 | static int au_procfs_plm_write_si(struct file *file, unsigned long id) | |
48 | { | |
49 | int err; | |
50 | struct super_block *sb; | |
51 | struct au_sbinfo *sbinfo; | |
52 | ||
53 | err = -EBUSY; | |
54 | if (unlikely(file->private_data)) | |
55 | goto out; | |
56 | ||
57 | sb = NULL; | |
58 | /* don't use au_sbilist_lock() here */ | |
59 | spin_lock(&au_sbilist.spin); | |
60 | hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list) | |
61 | if (id == sysaufs_si_id(sbinfo)) { | |
62 | kobject_get(&sbinfo->si_kobj); | |
63 | sb = sbinfo->si_sb; | |
64 | break; | |
65 | } | |
66 | spin_unlock(&au_sbilist.spin); | |
67 | ||
68 | err = -EINVAL; | |
69 | if (unlikely(!sb)) | |
70 | goto out; | |
71 | ||
72 | err = au_plink_maint_enter(sb); | |
73 | if (!err) | |
74 | /* keep kobject_get() */ | |
75 | file->private_data = sbinfo; | |
76 | else | |
77 | kobject_put(&sbinfo->si_kobj); | |
78 | out: | |
79 | return err; | |
80 | } | |
81 | ||
82 | /* | |
83 | * Accept a valid "si=xxxx" only. | |
84 | * Once it is accepted successfully, accept "clean" too. | |
85 | */ | |
86 | static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, | |
87 | size_t count, loff_t *ppos) | |
88 | { | |
89 | ssize_t err; | |
90 | unsigned long id; | |
91 | /* last newline is allowed */ | |
92 | char buf[3 + sizeof(unsigned long) * 2 + 1]; | |
93 | ||
94 | err = -EACCES; | |
95 | if (unlikely(!capable(CAP_SYS_ADMIN))) | |
96 | goto out; | |
97 | ||
98 | err = -EINVAL; | |
99 | if (unlikely(count > sizeof(buf))) | |
100 | goto out; | |
101 | ||
102 | err = copy_from_user(buf, ubuf, count); | |
103 | if (unlikely(err)) { | |
104 | err = -EFAULT; | |
105 | goto out; | |
106 | } | |
107 | buf[count] = 0; | |
108 | ||
109 | err = -EINVAL; | |
110 | if (!strcmp("clean", buf)) { | |
111 | au_procfs_plm_write_clean(file); | |
112 | goto out_success; | |
113 | } else if (unlikely(strncmp("si=", buf, 3))) | |
114 | goto out; | |
115 | ||
116 | err = kstrtoul(buf + 3, 16, &id); | |
117 | if (unlikely(err)) | |
118 | goto out; | |
119 | ||
120 | err = au_procfs_plm_write_si(file, id); | |
121 | if (unlikely(err)) | |
122 | goto out; | |
123 | ||
124 | out_success: | |
125 | err = count; /* success */ | |
126 | out: | |
127 | return err; | |
128 | } | |
129 | ||
130 | static const struct file_operations au_procfs_plm_fop = { | |
131 | .write = au_procfs_plm_write, | |
132 | .release = au_procfs_plm_release, | |
133 | .owner = THIS_MODULE | |
134 | }; | |
135 | ||
136 | /* ---------------------------------------------------------------------- */ | |
137 | ||
138 | static struct proc_dir_entry *au_procfs_dir; | |
139 | ||
140 | void au_procfs_fin(void) | |
141 | { | |
142 | remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); | |
143 | remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); | |
144 | } | |
145 | ||
146 | int __init au_procfs_init(void) | |
147 | { | |
148 | int err; | |
149 | struct proc_dir_entry *entry; | |
150 | ||
151 | err = -ENOMEM; | |
152 | au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); | |
153 | if (unlikely(!au_procfs_dir)) | |
154 | goto out; | |
155 | ||
156 | entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR, | |
157 | au_procfs_dir, &au_procfs_plm_fop); | |
158 | if (unlikely(!entry)) | |
159 | goto out_dir; | |
160 | ||
161 | err = 0; | |
162 | goto out; /* success */ | |
163 | ||
164 | ||
165 | out_dir: | |
166 | remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); | |
167 | out: | |
168 | return err; | |
169 | } |