diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2015-10-22 16:30:04 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2016-01-04 06:31:46 -0500 |
commit | 03607ace807b414eab46323c794b6fb8fcc2d48c (patch) | |
tree | a192ae4376e5db9eb02e2563d3c12a7312e677ba /fs/configfs | |
parent | 4ef7675344d687a0ef5b0d7c0cee12da005870c0 (diff) |
configfs: implement binary attributes
ConfigFS lacked binary attributes up until now. This patch
introduces support for binary attributes in a somewhat similar
manner of sysfs binary attributes albeit with changes that
fit the configfs usage model.
Problems that configfs binary attributes fix are everything that
requires a binary blob as part of the configuration of a resource,
such as bitstream loading for FPGAs, DTBs for dynamically created
devices etc.
Look at Documentation/filesystems/configfs/configfs.txt for internals
and howto use them.
This patch is against linux-next as of today that contains
Christoph's configfs rework.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[hch: folded a fix from Geert Uytterhoeven <geert+renesas@glider.be>]
[hch: a few tiny updates based on review feedback]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/configfs')
-rw-r--r-- | fs/configfs/configfs_internal.h | 14 | ||||
-rw-r--r-- | fs/configfs/dir.c | 18 | ||||
-rw-r--r-- | fs/configfs/file.c | 255 | ||||
-rw-r--r-- | fs/configfs/inode.c | 2 |
4 files changed, 276 insertions, 13 deletions
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index b65d1ef532d5..ccc31fa6f1a7 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
@@ -53,13 +53,14 @@ struct configfs_dirent { | |||
53 | #define CONFIGFS_ROOT 0x0001 | 53 | #define CONFIGFS_ROOT 0x0001 |
54 | #define CONFIGFS_DIR 0x0002 | 54 | #define CONFIGFS_DIR 0x0002 |
55 | #define CONFIGFS_ITEM_ATTR 0x0004 | 55 | #define CONFIGFS_ITEM_ATTR 0x0004 |
56 | #define CONFIGFS_ITEM_BIN_ATTR 0x0008 | ||
56 | #define CONFIGFS_ITEM_LINK 0x0020 | 57 | #define CONFIGFS_ITEM_LINK 0x0020 |
57 | #define CONFIGFS_USET_DIR 0x0040 | 58 | #define CONFIGFS_USET_DIR 0x0040 |
58 | #define CONFIGFS_USET_DEFAULT 0x0080 | 59 | #define CONFIGFS_USET_DEFAULT 0x0080 |
59 | #define CONFIGFS_USET_DROPPING 0x0100 | 60 | #define CONFIGFS_USET_DROPPING 0x0100 |
60 | #define CONFIGFS_USET_IN_MKDIR 0x0200 | 61 | #define CONFIGFS_USET_IN_MKDIR 0x0200 |
61 | #define CONFIGFS_USET_CREATING 0x0400 | 62 | #define CONFIGFS_USET_CREATING 0x0400 |
62 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) | 63 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR) |
63 | 64 | ||
64 | extern struct mutex configfs_symlink_mutex; | 65 | extern struct mutex configfs_symlink_mutex; |
65 | extern spinlock_t configfs_dirent_lock; | 66 | extern spinlock_t configfs_dirent_lock; |
@@ -72,6 +73,8 @@ extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *, | |||
72 | extern int configfs_create(struct dentry *, umode_t mode, void (*init)(struct inode *)); | 73 | extern int configfs_create(struct dentry *, umode_t mode, void (*init)(struct inode *)); |
73 | 74 | ||
74 | extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); | 75 | extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); |
76 | extern int configfs_create_bin_file(struct config_item *, | ||
77 | const struct configfs_bin_attribute *); | ||
75 | extern int configfs_make_dirent(struct configfs_dirent *, | 78 | extern int configfs_make_dirent(struct configfs_dirent *, |
76 | struct dentry *, void *, umode_t, int); | 79 | struct dentry *, void *, umode_t, int); |
77 | extern int configfs_dirent_is_ready(struct configfs_dirent *); | 80 | extern int configfs_dirent_is_ready(struct configfs_dirent *); |
@@ -88,7 +91,7 @@ extern void configfs_release_fs(void); | |||
88 | extern struct rw_semaphore configfs_rename_sem; | 91 | extern struct rw_semaphore configfs_rename_sem; |
89 | extern const struct file_operations configfs_dir_operations; | 92 | extern const struct file_operations configfs_dir_operations; |
90 | extern const struct file_operations configfs_file_operations; | 93 | extern const struct file_operations configfs_file_operations; |
91 | extern const struct file_operations bin_fops; | 94 | extern const struct file_operations configfs_bin_file_operations; |
92 | extern const struct inode_operations configfs_dir_inode_operations; | 95 | extern const struct inode_operations configfs_dir_inode_operations; |
93 | extern const struct inode_operations configfs_root_inode_operations; | 96 | extern const struct inode_operations configfs_root_inode_operations; |
94 | extern const struct inode_operations configfs_symlink_inode_operations; | 97 | extern const struct inode_operations configfs_symlink_inode_operations; |
@@ -119,6 +122,13 @@ static inline struct configfs_attribute * to_attr(struct dentry * dentry) | |||
119 | return ((struct configfs_attribute *) sd->s_element); | 122 | return ((struct configfs_attribute *) sd->s_element); |
120 | } | 123 | } |
121 | 124 | ||
125 | static inline struct configfs_bin_attribute *to_bin_attr(struct dentry *dentry) | ||
126 | { | ||
127 | struct configfs_attribute *attr = to_attr(dentry); | ||
128 | |||
129 | return container_of(attr, struct configfs_bin_attribute, cb_attr); | ||
130 | } | ||
131 | |||
122 | static inline struct config_item *configfs_get_config_item(struct dentry *dentry) | 132 | static inline struct config_item *configfs_get_config_item(struct dentry *dentry) |
123 | { | 133 | { |
124 | struct config_item * item = NULL; | 134 | struct config_item * item = NULL; |
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index a7a1b218f308..7ae97e83f121 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -255,6 +255,12 @@ static void configfs_init_file(struct inode * inode) | |||
255 | inode->i_fop = &configfs_file_operations; | 255 | inode->i_fop = &configfs_file_operations; |
256 | } | 256 | } |
257 | 257 | ||
258 | static void configfs_init_bin_file(struct inode *inode) | ||
259 | { | ||
260 | inode->i_size = 0; | ||
261 | inode->i_fop = &configfs_bin_file_operations; | ||
262 | } | ||
263 | |||
258 | static void init_symlink(struct inode * inode) | 264 | static void init_symlink(struct inode * inode) |
259 | { | 265 | { |
260 | inode->i_op = &configfs_symlink_inode_operations; | 266 | inode->i_op = &configfs_symlink_inode_operations; |
@@ -423,7 +429,9 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den | |||
423 | spin_unlock(&configfs_dirent_lock); | 429 | spin_unlock(&configfs_dirent_lock); |
424 | 430 | ||
425 | error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, | 431 | error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, |
426 | configfs_init_file); | 432 | (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) ? |
433 | configfs_init_bin_file : | ||
434 | configfs_init_file); | ||
427 | if (error) { | 435 | if (error) { |
428 | configfs_put(sd); | 436 | configfs_put(sd); |
429 | return error; | 437 | return error; |
@@ -583,6 +591,7 @@ static int populate_attrs(struct config_item *item) | |||
583 | { | 591 | { |
584 | struct config_item_type *t = item->ci_type; | 592 | struct config_item_type *t = item->ci_type; |
585 | struct configfs_attribute *attr; | 593 | struct configfs_attribute *attr; |
594 | struct configfs_bin_attribute *bin_attr; | ||
586 | int error = 0; | 595 | int error = 0; |
587 | int i; | 596 | int i; |
588 | 597 | ||
@@ -594,6 +603,13 @@ static int populate_attrs(struct config_item *item) | |||
594 | break; | 603 | break; |
595 | } | 604 | } |
596 | } | 605 | } |
606 | if (t->ct_bin_attrs) { | ||
607 | for (i = 0; (bin_attr = t->ct_bin_attrs[i]) != NULL; i++) { | ||
608 | error = configfs_create_bin_file(item, bin_attr); | ||
609 | if (error) | ||
610 | break; | ||
611 | } | ||
612 | } | ||
597 | 613 | ||
598 | if (error) | 614 | if (error) |
599 | detach_attrs(item); | 615 | detach_attrs(item); |
diff --git a/fs/configfs/file.c b/fs/configfs/file.c index d39099ea7df7..3687187c8ea5 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
31 | #include <linux/vmalloc.h> | ||
31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
32 | 33 | ||
33 | #include <linux/configfs.h> | 34 | #include <linux/configfs.h> |
@@ -48,6 +49,10 @@ struct configfs_buffer { | |||
48 | struct configfs_item_operations * ops; | 49 | struct configfs_item_operations * ops; |
49 | struct mutex mutex; | 50 | struct mutex mutex; |
50 | int needs_read_fill; | 51 | int needs_read_fill; |
52 | bool read_in_progress; | ||
53 | bool write_in_progress; | ||
54 | char *bin_buffer; | ||
55 | int bin_buffer_size; | ||
51 | }; | 56 | }; |
52 | 57 | ||
53 | 58 | ||
@@ -123,6 +128,87 @@ out: | |||
123 | return retval; | 128 | return retval; |
124 | } | 129 | } |
125 | 130 | ||
131 | /** | ||
132 | * configfs_read_bin_file - read a binary attribute. | ||
133 | * @file: file pointer. | ||
134 | * @buf: buffer to fill. | ||
135 | * @count: number of bytes to read. | ||
136 | * @ppos: starting offset in file. | ||
137 | * | ||
138 | * Userspace wants to read a binary attribute file. The attribute | ||
139 | * descriptor is in the file's ->d_fsdata. The target item is in the | ||
140 | * directory's ->d_fsdata. | ||
141 | * | ||
142 | * We check whether we need to refill the buffer. If so we will | ||
143 | * call the attributes' attr->read() twice. The first time we | ||
144 | * will pass a NULL as a buffer pointer, which the attributes' method | ||
145 | * will use to return the size of the buffer required. If no error | ||
146 | * occurs we will allocate the buffer using vmalloc and call | ||
147 | * attr->read() again passing that buffer as an argument. | ||
148 | * Then we just copy to user-space using simple_read_from_buffer. | ||
149 | */ | ||
150 | |||
151 | static ssize_t | ||
152 | configfs_read_bin_file(struct file *file, char __user *buf, | ||
153 | size_t count, loff_t *ppos) | ||
154 | { | ||
155 | struct configfs_buffer *buffer = file->private_data; | ||
156 | struct dentry *dentry = file->f_path.dentry; | ||
157 | struct config_item *item = to_item(dentry->d_parent); | ||
158 | struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); | ||
159 | ssize_t retval = 0; | ||
160 | ssize_t len = min_t(size_t, count, PAGE_SIZE); | ||
161 | |||
162 | mutex_lock(&buffer->mutex); | ||
163 | |||
164 | /* we don't support switching read/write modes */ | ||
165 | if (buffer->write_in_progress) { | ||
166 | retval = -ETXTBSY; | ||
167 | goto out; | ||
168 | } | ||
169 | buffer->read_in_progress = 1; | ||
170 | |||
171 | if (buffer->needs_read_fill) { | ||
172 | /* perform first read with buf == NULL to get extent */ | ||
173 | len = bin_attr->read(item, NULL, 0); | ||
174 | if (len <= 0) { | ||
175 | retval = len; | ||
176 | goto out; | ||
177 | } | ||
178 | |||
179 | /* do not exceed the maximum value */ | ||
180 | if (bin_attr->cb_max_size && len > bin_attr->cb_max_size) { | ||
181 | retval = -EFBIG; | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | buffer->bin_buffer = vmalloc(len); | ||
186 | if (buffer->bin_buffer == NULL) { | ||
187 | retval = -ENOMEM; | ||
188 | goto out; | ||
189 | } | ||
190 | buffer->bin_buffer_size = len; | ||
191 | |||
192 | /* perform second read to fill buffer */ | ||
193 | len = bin_attr->read(item, buffer->bin_buffer, len); | ||
194 | if (len < 0) { | ||
195 | retval = len; | ||
196 | vfree(buffer->bin_buffer); | ||
197 | buffer->bin_buffer_size = 0; | ||
198 | buffer->bin_buffer = NULL; | ||
199 | goto out; | ||
200 | } | ||
201 | |||
202 | buffer->needs_read_fill = 0; | ||
203 | } | ||
204 | |||
205 | retval = simple_read_from_buffer(buf, count, ppos, buffer->bin_buffer, | ||
206 | buffer->bin_buffer_size); | ||
207 | out: | ||
208 | mutex_unlock(&buffer->mutex); | ||
209 | return retval; | ||
210 | } | ||
211 | |||
126 | 212 | ||
127 | /** | 213 | /** |
128 | * fill_write_buffer - copy buffer from userspace. | 214 | * fill_write_buffer - copy buffer from userspace. |
@@ -209,10 +295,80 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof | |||
209 | return len; | 295 | return len; |
210 | } | 296 | } |
211 | 297 | ||
212 | static int check_perm(struct inode * inode, struct file * file) | 298 | /** |
299 | * configfs_write_bin_file - write a binary attribute. | ||
300 | * @file: file pointer | ||
301 | * @buf: data to write | ||
302 | * @count: number of bytes | ||
303 | * @ppos: starting offset | ||
304 | * | ||
305 | * Writing to a binary attribute file is similar to a normal read. | ||
306 | * We buffer the consecutive writes (binary attribute files do not | ||
307 | * support lseek) in a continuously growing buffer, but we don't | ||
308 | * commit until the close of the file. | ||
309 | */ | ||
310 | |||
311 | static ssize_t | ||
312 | configfs_write_bin_file(struct file *file, const char __user *buf, | ||
313 | size_t count, loff_t *ppos) | ||
314 | { | ||
315 | struct configfs_buffer *buffer = file->private_data; | ||
316 | struct dentry *dentry = file->f_path.dentry; | ||
317 | struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); | ||
318 | void *tbuf = NULL; | ||
319 | ssize_t len; | ||
320 | |||
321 | mutex_lock(&buffer->mutex); | ||
322 | |||
323 | /* we don't support switching read/write modes */ | ||
324 | if (buffer->read_in_progress) { | ||
325 | len = -ETXTBSY; | ||
326 | goto out; | ||
327 | } | ||
328 | buffer->write_in_progress = 1; | ||
329 | |||
330 | /* buffer grows? */ | ||
331 | if (*ppos + count > buffer->bin_buffer_size) { | ||
332 | |||
333 | if (bin_attr->cb_max_size && | ||
334 | *ppos + count > bin_attr->cb_max_size) { | ||
335 | len = -EFBIG; | ||
336 | } | ||
337 | |||
338 | tbuf = vmalloc(*ppos + count); | ||
339 | if (tbuf == NULL) { | ||
340 | len = -ENOMEM; | ||
341 | goto out; | ||
342 | } | ||
343 | |||
344 | /* copy old contents */ | ||
345 | if (buffer->bin_buffer) { | ||
346 | memcpy(tbuf, buffer->bin_buffer, | ||
347 | buffer->bin_buffer_size); | ||
348 | vfree(buffer->bin_buffer); | ||
349 | } | ||
350 | |||
351 | /* clear the new area */ | ||
352 | memset(tbuf + buffer->bin_buffer_size, 0, | ||
353 | *ppos + count - buffer->bin_buffer_size); | ||
354 | buffer->bin_buffer = tbuf; | ||
355 | buffer->bin_buffer_size = *ppos + count; | ||
356 | } | ||
357 | |||
358 | len = simple_write_to_buffer(buffer->bin_buffer, | ||
359 | buffer->bin_buffer_size, ppos, buf, count); | ||
360 | if (len > 0) | ||
361 | *ppos += len; | ||
362 | out: | ||
363 | mutex_unlock(&buffer->mutex); | ||
364 | return len; | ||
365 | } | ||
366 | |||
367 | static int check_perm(struct inode * inode, struct file * file, int type) | ||
213 | { | 368 | { |
214 | struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent); | 369 | struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent); |
215 | struct configfs_attribute * attr = to_attr(file->f_path.dentry); | 370 | struct configfs_attribute * attr = to_attr(file->f_path.dentry); |
371 | struct configfs_bin_attribute *bin_attr = NULL; | ||
216 | struct configfs_buffer * buffer; | 372 | struct configfs_buffer * buffer; |
217 | struct configfs_item_operations * ops = NULL; | 373 | struct configfs_item_operations * ops = NULL; |
218 | int error = 0; | 374 | int error = 0; |
@@ -220,6 +376,9 @@ static int check_perm(struct inode * inode, struct file * file) | |||
220 | if (!item || !attr) | 376 | if (!item || !attr) |
221 | goto Einval; | 377 | goto Einval; |
222 | 378 | ||
379 | if (type & CONFIGFS_ITEM_BIN_ATTR) | ||
380 | bin_attr = to_bin_attr(file->f_path.dentry); | ||
381 | |||
223 | /* Grab the module reference for this attribute if we have one */ | 382 | /* Grab the module reference for this attribute if we have one */ |
224 | if (!try_module_get(attr->ca_owner)) { | 383 | if (!try_module_get(attr->ca_owner)) { |
225 | error = -ENODEV; | 384 | error = -ENODEV; |
@@ -236,9 +395,14 @@ static int check_perm(struct inode * inode, struct file * file) | |||
236 | * and we must have a store method. | 395 | * and we must have a store method. |
237 | */ | 396 | */ |
238 | if (file->f_mode & FMODE_WRITE) { | 397 | if (file->f_mode & FMODE_WRITE) { |
239 | if (!(inode->i_mode & S_IWUGO) || !attr->store) | 398 | if (!(inode->i_mode & S_IWUGO)) |
399 | goto Eaccess; | ||
400 | |||
401 | if ((type & CONFIGFS_ITEM_ATTR) && !attr->store) | ||
240 | goto Eaccess; | 402 | goto Eaccess; |
241 | 403 | ||
404 | if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->write) | ||
405 | goto Eaccess; | ||
242 | } | 406 | } |
243 | 407 | ||
244 | /* File needs read support. | 408 | /* File needs read support. |
@@ -246,7 +410,13 @@ static int check_perm(struct inode * inode, struct file * file) | |||
246 | * must be a show method for it. | 410 | * must be a show method for it. |
247 | */ | 411 | */ |
248 | if (file->f_mode & FMODE_READ) { | 412 | if (file->f_mode & FMODE_READ) { |
249 | if (!(inode->i_mode & S_IRUGO) || !attr->show) | 413 | if (!(inode->i_mode & S_IRUGO)) |
414 | goto Eaccess; | ||
415 | |||
416 | if ((type & CONFIGFS_ITEM_ATTR) && !attr->show) | ||
417 | goto Eaccess; | ||
418 | |||
419 | if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->read) | ||
250 | goto Eaccess; | 420 | goto Eaccess; |
251 | } | 421 | } |
252 | 422 | ||
@@ -260,6 +430,8 @@ static int check_perm(struct inode * inode, struct file * file) | |||
260 | } | 430 | } |
261 | mutex_init(&buffer->mutex); | 431 | mutex_init(&buffer->mutex); |
262 | buffer->needs_read_fill = 1; | 432 | buffer->needs_read_fill = 1; |
433 | buffer->read_in_progress = 0; | ||
434 | buffer->write_in_progress = 0; | ||
263 | buffer->ops = ops; | 435 | buffer->ops = ops; |
264 | file->private_data = buffer; | 436 | file->private_data = buffer; |
265 | goto Done; | 437 | goto Done; |
@@ -277,12 +449,7 @@ static int check_perm(struct inode * inode, struct file * file) | |||
277 | return error; | 449 | return error; |
278 | } | 450 | } |
279 | 451 | ||
280 | static int configfs_open_file(struct inode * inode, struct file * filp) | 452 | static int configfs_release(struct inode *inode, struct file *filp) |
281 | { | ||
282 | return check_perm(inode,filp); | ||
283 | } | ||
284 | |||
285 | static int configfs_release(struct inode * inode, struct file * filp) | ||
286 | { | 453 | { |
287 | struct config_item * item = to_item(filp->f_path.dentry->d_parent); | 454 | struct config_item * item = to_item(filp->f_path.dentry->d_parent); |
288 | struct configfs_attribute * attr = to_attr(filp->f_path.dentry); | 455 | struct configfs_attribute * attr = to_attr(filp->f_path.dentry); |
@@ -303,6 +470,47 @@ static int configfs_release(struct inode * inode, struct file * filp) | |||
303 | return 0; | 470 | return 0; |
304 | } | 471 | } |
305 | 472 | ||
473 | static int configfs_open_file(struct inode *inode, struct file *filp) | ||
474 | { | ||
475 | return check_perm(inode, filp, CONFIGFS_ITEM_ATTR); | ||
476 | } | ||
477 | |||
478 | static int configfs_open_bin_file(struct inode *inode, struct file *filp) | ||
479 | { | ||
480 | return check_perm(inode, filp, CONFIGFS_ITEM_BIN_ATTR); | ||
481 | } | ||
482 | |||
483 | static int configfs_release_bin_file(struct inode *inode, struct file *filp) | ||
484 | { | ||
485 | struct configfs_buffer *buffer = filp->private_data; | ||
486 | struct dentry *dentry = filp->f_path.dentry; | ||
487 | struct config_item *item = to_item(dentry->d_parent); | ||
488 | struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); | ||
489 | ssize_t len = 0; | ||
490 | int ret; | ||
491 | |||
492 | buffer->read_in_progress = 0; | ||
493 | |||
494 | if (buffer->write_in_progress) { | ||
495 | buffer->write_in_progress = 0; | ||
496 | |||
497 | len = bin_attr->write(item, buffer->bin_buffer, | ||
498 | buffer->bin_buffer_size); | ||
499 | |||
500 | /* vfree on NULL is safe */ | ||
501 | vfree(buffer->bin_buffer); | ||
502 | buffer->bin_buffer = NULL; | ||
503 | buffer->bin_buffer_size = 0; | ||
504 | buffer->needs_read_fill = 1; | ||
505 | } | ||
506 | |||
507 | ret = configfs_release(inode, filp); | ||
508 | if (len < 0) | ||
509 | return len; | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | |||
306 | const struct file_operations configfs_file_operations = { | 514 | const struct file_operations configfs_file_operations = { |
307 | .read = configfs_read_file, | 515 | .read = configfs_read_file, |
308 | .write = configfs_write_file, | 516 | .write = configfs_write_file, |
@@ -311,6 +519,14 @@ const struct file_operations configfs_file_operations = { | |||
311 | .release = configfs_release, | 519 | .release = configfs_release, |
312 | }; | 520 | }; |
313 | 521 | ||
522 | const struct file_operations configfs_bin_file_operations = { | ||
523 | .read = configfs_read_bin_file, | ||
524 | .write = configfs_write_bin_file, | ||
525 | .llseek = NULL, /* bin file is not seekable */ | ||
526 | .open = configfs_open_bin_file, | ||
527 | .release = configfs_release_bin_file, | ||
528 | }; | ||
529 | |||
314 | /** | 530 | /** |
315 | * configfs_create_file - create an attribute file for an item. | 531 | * configfs_create_file - create an attribute file for an item. |
316 | * @item: item we're creating for. | 532 | * @item: item we're creating for. |
@@ -332,3 +548,24 @@ int configfs_create_file(struct config_item * item, const struct configfs_attrib | |||
332 | return error; | 548 | return error; |
333 | } | 549 | } |
334 | 550 | ||
551 | /** | ||
552 | * configfs_create_bin_file - create a binary attribute file for an item. | ||
553 | * @item: item we're creating for. | ||
554 | * @attr: atrribute descriptor. | ||
555 | */ | ||
556 | |||
557 | int configfs_create_bin_file(struct config_item *item, | ||
558 | const struct configfs_bin_attribute *bin_attr) | ||
559 | { | ||
560 | struct dentry *dir = item->ci_dentry; | ||
561 | struct configfs_dirent *parent_sd = dir->d_fsdata; | ||
562 | umode_t mode = (bin_attr->cb_attr.ca_mode & S_IALLUGO) | S_IFREG; | ||
563 | int error = 0; | ||
564 | |||
565 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL); | ||
566 | error = configfs_make_dirent(parent_sd, NULL, (void *) bin_attr, mode, | ||
567 | CONFIGFS_ITEM_BIN_ATTR); | ||
568 | mutex_unlock(&dir->d_inode->i_mutex); | ||
569 | |||
570 | return error; | ||
571 | } | ||
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index eae87575e681..0cc810e9dccc 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
@@ -218,7 +218,7 @@ const unsigned char * configfs_get_name(struct configfs_dirent *sd) | |||
218 | if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) | 218 | if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) |
219 | return sd->s_dentry->d_name.name; | 219 | return sd->s_dentry->d_name.name; |
220 | 220 | ||
221 | if (sd->s_type & CONFIGFS_ITEM_ATTR) { | 221 | if (sd->s_type & (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)) { |
222 | attr = sd->s_element; | 222 | attr = sd->s_element; |
223 | return attr->ca_name; | 223 | return attr->ca_name; |
224 | } | 224 | } |