Merge branches 'pandora-3.2-aufs', 'pandora-3.2-mru', 'pandora-3.2-picks' and 'pandor...
[pandora-kernel.git] / fs / aufs / sysfs.c
1 /*
2  * Copyright (C) 2005-2012 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)
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         path.mnt = br->br_mnt;
96         path.dentry = au_h_dptr(root, bindex);
97         au_seq_path(seq, &path);
98         di_read_unlock(root, !AuLock_IR);
99         perm = au_optstr_br_perm(br->br_perm);
100         if (perm) {
101                 err = seq_printf(seq, "=%s\n", perm);
102                 kfree(perm);
103                 if (err == -1)
104                         err = -E2BIG;
105         } else
106                 err = -ENOMEM;
107         return err;
108 }
109
110 /* ---------------------------------------------------------------------- */
111
112 static struct seq_file *au_seq(char *p, ssize_t len)
113 {
114         struct seq_file *seq;
115
116         seq = kzalloc(sizeof(*seq), GFP_NOFS);
117         if (seq) {
118                 /* mutex_init(&seq.lock); */
119                 seq->buf = p;
120                 seq->size = len;
121                 return seq; /* success */
122         }
123
124         seq = ERR_PTR(-ENOMEM);
125         return seq;
126 }
127
128 #define SysaufsBr_PREFIX "br"
129
130 /* todo: file size may exceed PAGE_SIZE */
131 ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
132                         char *buf)
133 {
134         ssize_t err;
135         long l;
136         aufs_bindex_t bend;
137         struct au_sbinfo *sbinfo;
138         struct super_block *sb;
139         struct seq_file *seq;
140         char *name;
141         struct attribute **cattr;
142
143         sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
144         sb = sbinfo->si_sb;
145
146         /*
147          * prevent a race condition between sysfs and aufs.
148          * for instance, sysfs_file_read() calls sysfs_get_active_two() which
149          * prohibits maintaining the sysfs entries.
150          * hew we acquire read lock after sysfs_get_active_two().
151          * on the other hand, the remount process may maintain the sysfs/aufs
152          * entries after acquiring write lock.
153          * it can cause a deadlock.
154          * simply we gave up processing read here.
155          */
156         err = -EBUSY;
157         if (unlikely(!si_noflush_read_trylock(sb)))
158                 goto out;
159
160         seq = au_seq(buf, PAGE_SIZE);
161         err = PTR_ERR(seq);
162         if (IS_ERR(seq))
163                 goto out_unlock;
164
165         name = (void *)attr->name;
166         cattr = sysaufs_si_attrs;
167         while (*cattr) {
168                 if (!strcmp(name, (*cattr)->name)) {
169                         err = container_of(*cattr, struct sysaufs_si_attr, attr)
170                                 ->show(seq, sb);
171                         goto out_seq;
172                 }
173                 cattr++;
174         }
175
176         bend = au_sbend(sb);
177         if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) {
178                 name += sizeof(SysaufsBr_PREFIX) - 1;
179                 err = kstrtol(name, 10, &l);
180                 if (!err) {
181                         if (l <= bend)
182                                 err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l);
183                         else
184                                 err = -ENOENT;
185                 }
186                 goto out_seq;
187         }
188         BUG();
189
190 out_seq:
191         if (!err) {
192                 err = seq->count;
193                 /* sysfs limit */
194                 if (unlikely(err == PAGE_SIZE))
195                         err = -EFBIG;
196         }
197         kfree(seq);
198 out_unlock:
199         si_read_unlock(sb);
200 out:
201         return err;
202 }
203
204 /* ---------------------------------------------------------------------- */
205
206 void sysaufs_br_init(struct au_branch *br)
207 {
208         struct attribute *attr = &br->br_attr;
209
210         sysfs_attr_init(attr);
211         attr->name = br->br_name;
212         attr->mode = S_IRUGO;
213 }
214
215 void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
216 {
217         struct au_branch *br;
218         struct kobject *kobj;
219         aufs_bindex_t bend;
220
221         dbgaufs_brs_del(sb, bindex);
222
223         if (!sysaufs_brs)
224                 return;
225
226         kobj = &au_sbi(sb)->si_kobj;
227         bend = au_sbend(sb);
228         for (; bindex <= bend; bindex++) {
229                 br = au_sbr(sb, bindex);
230                 sysfs_remove_file(kobj, &br->br_attr);
231         }
232 }
233
234 void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
235 {
236         int err;
237         aufs_bindex_t bend;
238         struct kobject *kobj;
239         struct au_branch *br;
240
241         dbgaufs_brs_add(sb, bindex);
242
243         if (!sysaufs_brs)
244                 return;
245
246         kobj = &au_sbi(sb)->si_kobj;
247         bend = au_sbend(sb);
248         for (; bindex <= bend; bindex++) {
249                 br = au_sbr(sb, bindex);
250                 snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX
251                          "%d", bindex);
252                 err = sysfs_create_file(kobj, &br->br_attr);
253                 if (unlikely(err))
254                         pr_warning("failed %s under sysfs(%d)\n",
255                                    br->br_name, err);
256         }
257 }