update aufs to it's latest standalone 3.2 branch
[pandora-kernel.git] / fs / aufs / sysfs.c
1 /*
2  * Copyright (C) 2005-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  * sysfs interface
21  */
22
23 #include <linux/seq_file.h>
24 #include "aufs.h"
25
26 #ifdef CONFIG_AUFS_FS_MODULE
27 /* this entry violates the "one line per file" policy of sysfs */
28 static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr,
29                            char *buf)
30 {
31         ssize_t err;
32         static char *conf =
33 /* this file is generated at compiling */
34 #include "conf.str"
35                 ;
36
37         err = snprintf(buf, PAGE_SIZE, conf);
38         if (unlikely(err >= PAGE_SIZE))
39                 err = -EFBIG;
40         return err;
41 }
42
43 static struct kobj_attribute au_config_attr = __ATTR_RO(config);
44 #endif
45
46 static struct attribute *au_attr[] = {
47 #ifdef CONFIG_AUFS_FS_MODULE
48         &au_config_attr.attr,
49 #endif
50         NULL,   /* need to NULL terminate the list of attributes */
51 };
52
53 static struct attribute_group sysaufs_attr_group_body = {
54         .attrs = au_attr
55 };
56
57 struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body;
58
59 /* ---------------------------------------------------------------------- */
60
61 int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
62 {
63         int err;
64
65         SiMustAnyLock(sb);
66
67         err = 0;
68         if (au_opt_test(au_mntflags(sb), XINO)) {
69                 err = au_xino_path(seq, au_sbi(sb)->si_xib);
70                 seq_putc(seq, '\n');
71         }
72         return err;
73 }
74
75 /*
76  * the lifetime of branch is independent from the entry under sysfs.
77  * sysfs handles the lifetime of the entry, and never call ->show() after it is
78  * unlinked.
79  */
80 static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
81                          aufs_bindex_t bindex, int idx)
82 {
83         int err;
84         struct path path;
85         struct dentry *root;
86         struct au_branch *br;
87         char *perm;
88
89         AuDbg("b%d\n", bindex);
90
91         err = 0;
92         root = sb->s_root;
93         di_read_lock_parent(root, !AuLock_IR);
94         br = au_sbr(sb, bindex);
95
96         switch (idx) {
97         case AuBrSysfs_BR:
98                 path.mnt = au_br_mnt(br);
99                 path.dentry = au_h_dptr(root, bindex);
100                 au_seq_path(seq, &path);
101                 di_read_unlock(root, !AuLock_IR);
102                 perm = au_optstr_br_perm(br->br_perm);
103                 if (perm) {
104                         err = seq_printf(seq, "=%s\n", perm);
105                         kfree(perm);
106                         if (err == -1)
107                                 err = -E2BIG;
108                 } else
109                         err = -ENOMEM;
110                 break;
111         case AuBrSysfs_BRID:
112                 err = seq_printf(seq, "%d\n", br->br_id);
113                 di_read_unlock(root, !AuLock_IR);
114                 if (err == -1)
115                         err = -E2BIG;
116                 break;
117         }
118
119         return err;
120 }
121
122 /* ---------------------------------------------------------------------- */
123
124 static struct seq_file *au_seq(char *p, ssize_t len)
125 {
126         struct seq_file *seq;
127
128         seq = kzalloc(sizeof(*seq), GFP_NOFS);
129         if (seq) {
130                 /* mutex_init(&seq.lock); */
131                 seq->buf = p;
132                 seq->size = len;
133                 return seq; /* success */
134         }
135
136         seq = ERR_PTR(-ENOMEM);
137         return seq;
138 }
139
140 #define SysaufsBr_PREFIX        "br"
141 #define SysaufsBrid_PREFIX      "brid"
142
143 /* todo: file size may exceed PAGE_SIZE */
144 ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
145                         char *buf)
146 {
147         ssize_t err;
148         int idx;
149         long l;
150         aufs_bindex_t bend;
151         struct au_sbinfo *sbinfo;
152         struct super_block *sb;
153         struct seq_file *seq;
154         char *name;
155         struct attribute **cattr;
156
157         sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
158         sb = sbinfo->si_sb;
159
160         /*
161          * prevent a race condition between sysfs and aufs.
162          * for instance, sysfs_file_read() calls sysfs_get_active_two() which
163          * prohibits maintaining the sysfs entries.
164          * hew we acquire read lock after sysfs_get_active_two().
165          * on the other hand, the remount process may maintain the sysfs/aufs
166          * entries after acquiring write lock.
167          * it can cause a deadlock.
168          * simply we gave up processing read here.
169          */
170         err = -EBUSY;
171         if (unlikely(!si_noflush_read_trylock(sb)))
172                 goto out;
173
174         seq = au_seq(buf, PAGE_SIZE);
175         err = PTR_ERR(seq);
176         if (IS_ERR(seq))
177                 goto out_unlock;
178
179         name = (void *)attr->name;
180         cattr = sysaufs_si_attrs;
181         while (*cattr) {
182                 if (!strcmp(name, (*cattr)->name)) {
183                         err = container_of(*cattr, struct sysaufs_si_attr, attr)
184                                 ->show(seq, sb);
185                         goto out_seq;
186                 }
187                 cattr++;
188         }
189
190         if (!strncmp(name, SysaufsBrid_PREFIX,
191                      sizeof(SysaufsBrid_PREFIX) - 1)) {
192                 idx = AuBrSysfs_BRID;
193                 name += sizeof(SysaufsBrid_PREFIX) - 1;
194         } else if (!strncmp(name, SysaufsBr_PREFIX,
195                             sizeof(SysaufsBr_PREFIX) - 1)) {
196                 idx = AuBrSysfs_BR;
197                 name += sizeof(SysaufsBr_PREFIX) - 1;
198         } else
199                   BUG();
200
201         err = kstrtol(name, 10, &l);
202         if (!err) {
203                 bend = au_sbend(sb);
204                 if (l <= bend)
205                         err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx);
206                 else
207                         err = -ENOENT;
208         }
209
210 out_seq:
211         if (!err) {
212                 err = seq->count;
213                 /* sysfs limit */
214                 if (unlikely(err == PAGE_SIZE))
215                         err = -EFBIG;
216         }
217         kfree(seq);
218 out_unlock:
219         si_read_unlock(sb);
220 out:
221         return err;
222 }
223
224 /* ---------------------------------------------------------------------- */
225
226 void sysaufs_br_init(struct au_branch *br)
227 {
228         int i;
229         struct au_brsysfs *br_sysfs;
230         struct attribute *attr;
231
232         br_sysfs = br->br_sysfs;
233         for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
234                 attr = &br_sysfs->attr;
235                 sysfs_attr_init(attr);
236                 attr->name = br_sysfs->name;
237                 attr->mode = S_IRUGO;
238                 br_sysfs++;
239         }
240 }
241
242 void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
243 {
244         struct au_branch *br;
245         struct kobject *kobj;
246         struct au_brsysfs *br_sysfs;
247         int i;
248         aufs_bindex_t bend;
249
250         dbgaufs_brs_del(sb, bindex);
251
252         if (!sysaufs_brs)
253                 return;
254
255         kobj = &au_sbi(sb)->si_kobj;
256         bend = au_sbend(sb);
257         for (; bindex <= bend; bindex++) {
258                 br = au_sbr(sb, bindex);
259                 br_sysfs = br->br_sysfs;
260                 for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
261                         sysfs_remove_file(kobj, &br_sysfs->attr);
262                         br_sysfs++;
263                 }
264         }
265 }
266
267 void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
268 {
269         int err, i;
270         aufs_bindex_t bend;
271         struct kobject *kobj;
272         struct au_branch *br;
273         struct au_brsysfs *br_sysfs;
274
275         dbgaufs_brs_add(sb, bindex);
276
277         if (!sysaufs_brs)
278                 return;
279
280         kobj = &au_sbi(sb)->si_kobj;
281         bend = au_sbend(sb);
282         for (; bindex <= bend; bindex++) {
283                 br = au_sbr(sb, bindex);
284                 br_sysfs = br->br_sysfs;
285                 snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name),
286                          SysaufsBr_PREFIX "%d", bindex);
287                 snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name),
288                          SysaufsBrid_PREFIX "%d", bindex);
289                 for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
290                         err = sysfs_create_file(kobj, &br_sysfs->attr);
291                         if (unlikely(err))
292                                 pr_warn("failed %s under sysfs(%d)\n",
293                                         br_sysfs->name, err);
294                         br_sysfs++;
295                 }
296         }
297 }