1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* -*- mode: c; c-basic-offset: 8; -*-
3*4882a593Smuzhiyun * vim: noexpandtab sw=8 ts=8 sts=0:
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * file.c - operations for regular (text) files.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Based on sysfs:
8*4882a593Smuzhiyun * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * configfs Copyright (C) 2005 Oracle. All rights reserved.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/fs.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/mutex.h>
17*4882a593Smuzhiyun #include <linux/vmalloc.h>
18*4882a593Smuzhiyun #include <linux/uaccess.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/configfs.h>
21*4882a593Smuzhiyun #include "configfs_internal.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /*
24*4882a593Smuzhiyun * A simple attribute can only be 4096 characters. Why 4k? Because the
25*4882a593Smuzhiyun * original code limited it to PAGE_SIZE. That's a bad idea, though,
26*4882a593Smuzhiyun * because an attribute of 16k on ia64 won't work on x86. So we limit to
27*4882a593Smuzhiyun * 4k, our minimum common page size.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun #define SIMPLE_ATTR_SIZE 4096
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct configfs_buffer {
32*4882a593Smuzhiyun size_t count;
33*4882a593Smuzhiyun loff_t pos;
34*4882a593Smuzhiyun char * page;
35*4882a593Smuzhiyun struct configfs_item_operations * ops;
36*4882a593Smuzhiyun struct mutex mutex;
37*4882a593Smuzhiyun int needs_read_fill;
38*4882a593Smuzhiyun bool read_in_progress;
39*4882a593Smuzhiyun bool write_in_progress;
40*4882a593Smuzhiyun char *bin_buffer;
41*4882a593Smuzhiyun int bin_buffer_size;
42*4882a593Smuzhiyun int cb_max_size;
43*4882a593Smuzhiyun struct config_item *item;
44*4882a593Smuzhiyun struct module *owner;
45*4882a593Smuzhiyun union {
46*4882a593Smuzhiyun struct configfs_attribute *attr;
47*4882a593Smuzhiyun struct configfs_bin_attribute *bin_attr;
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun
to_frag(struct file * file)51*4882a593Smuzhiyun static inline struct configfs_fragment *to_frag(struct file *file)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun struct configfs_dirent *sd = file->f_path.dentry->d_fsdata;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun return sd->s_frag;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
fill_read_buffer(struct file * file,struct configfs_buffer * buffer)58*4882a593Smuzhiyun static int fill_read_buffer(struct file *file, struct configfs_buffer *buffer)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun struct configfs_fragment *frag = to_frag(file);
61*4882a593Smuzhiyun ssize_t count = -ENOENT;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (!buffer->page)
64*4882a593Smuzhiyun buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
65*4882a593Smuzhiyun if (!buffer->page)
66*4882a593Smuzhiyun return -ENOMEM;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun down_read(&frag->frag_sem);
69*4882a593Smuzhiyun if (!frag->frag_dead)
70*4882a593Smuzhiyun count = buffer->attr->show(buffer->item, buffer->page);
71*4882a593Smuzhiyun up_read(&frag->frag_sem);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (count < 0)
74*4882a593Smuzhiyun return count;
75*4882a593Smuzhiyun if (WARN_ON_ONCE(count > (ssize_t)SIMPLE_ATTR_SIZE))
76*4882a593Smuzhiyun return -EIO;
77*4882a593Smuzhiyun buffer->needs_read_fill = 0;
78*4882a593Smuzhiyun buffer->count = count;
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /**
83*4882a593Smuzhiyun * configfs_read_file - read an attribute.
84*4882a593Smuzhiyun * @file: file pointer.
85*4882a593Smuzhiyun * @buf: buffer to fill.
86*4882a593Smuzhiyun * @count: number of bytes to read.
87*4882a593Smuzhiyun * @ppos: starting offset in file.
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun * Userspace wants to read an attribute file. The attribute descriptor
90*4882a593Smuzhiyun * is in the file's ->d_fsdata. The target item is in the directory's
91*4882a593Smuzhiyun * ->d_fsdata.
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun * We call fill_read_buffer() to allocate and fill the buffer from the
94*4882a593Smuzhiyun * item's show() method exactly once (if the read is happening from
95*4882a593Smuzhiyun * the beginning of the file). That should fill the entire buffer with
96*4882a593Smuzhiyun * all the data the item has to offer for that attribute.
97*4882a593Smuzhiyun * We then call flush_read_buffer() to copy the buffer to userspace
98*4882a593Smuzhiyun * in the increments specified.
99*4882a593Smuzhiyun */
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun static ssize_t
configfs_read_file(struct file * file,char __user * buf,size_t count,loff_t * ppos)102*4882a593Smuzhiyun configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun struct configfs_buffer *buffer = file->private_data;
105*4882a593Smuzhiyun ssize_t retval = 0;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun mutex_lock(&buffer->mutex);
108*4882a593Smuzhiyun if (buffer->needs_read_fill) {
109*4882a593Smuzhiyun retval = fill_read_buffer(file, buffer);
110*4882a593Smuzhiyun if (retval)
111*4882a593Smuzhiyun goto out;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
114*4882a593Smuzhiyun __func__, count, *ppos, buffer->page);
115*4882a593Smuzhiyun retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
116*4882a593Smuzhiyun buffer->count);
117*4882a593Smuzhiyun out:
118*4882a593Smuzhiyun mutex_unlock(&buffer->mutex);
119*4882a593Smuzhiyun return retval;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /**
123*4882a593Smuzhiyun * configfs_read_bin_file - read a binary attribute.
124*4882a593Smuzhiyun * @file: file pointer.
125*4882a593Smuzhiyun * @buf: buffer to fill.
126*4882a593Smuzhiyun * @count: number of bytes to read.
127*4882a593Smuzhiyun * @ppos: starting offset in file.
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun * Userspace wants to read a binary attribute file. The attribute
130*4882a593Smuzhiyun * descriptor is in the file's ->d_fsdata. The target item is in the
131*4882a593Smuzhiyun * directory's ->d_fsdata.
132*4882a593Smuzhiyun *
133*4882a593Smuzhiyun * We check whether we need to refill the buffer. If so we will
134*4882a593Smuzhiyun * call the attributes' attr->read() twice. The first time we
135*4882a593Smuzhiyun * will pass a NULL as a buffer pointer, which the attributes' method
136*4882a593Smuzhiyun * will use to return the size of the buffer required. If no error
137*4882a593Smuzhiyun * occurs we will allocate the buffer using vmalloc and call
138*4882a593Smuzhiyun * attr->read() again passing that buffer as an argument.
139*4882a593Smuzhiyun * Then we just copy to user-space using simple_read_from_buffer.
140*4882a593Smuzhiyun */
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun static ssize_t
configfs_read_bin_file(struct file * file,char __user * buf,size_t count,loff_t * ppos)143*4882a593Smuzhiyun configfs_read_bin_file(struct file *file, char __user *buf,
144*4882a593Smuzhiyun size_t count, loff_t *ppos)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct configfs_fragment *frag = to_frag(file);
147*4882a593Smuzhiyun struct configfs_buffer *buffer = file->private_data;
148*4882a593Smuzhiyun ssize_t retval = 0;
149*4882a593Smuzhiyun ssize_t len = min_t(size_t, count, PAGE_SIZE);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun mutex_lock(&buffer->mutex);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /* we don't support switching read/write modes */
154*4882a593Smuzhiyun if (buffer->write_in_progress) {
155*4882a593Smuzhiyun retval = -ETXTBSY;
156*4882a593Smuzhiyun goto out;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun buffer->read_in_progress = true;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (buffer->needs_read_fill) {
161*4882a593Smuzhiyun /* perform first read with buf == NULL to get extent */
162*4882a593Smuzhiyun down_read(&frag->frag_sem);
163*4882a593Smuzhiyun if (!frag->frag_dead)
164*4882a593Smuzhiyun len = buffer->bin_attr->read(buffer->item, NULL, 0);
165*4882a593Smuzhiyun else
166*4882a593Smuzhiyun len = -ENOENT;
167*4882a593Smuzhiyun up_read(&frag->frag_sem);
168*4882a593Smuzhiyun if (len <= 0) {
169*4882a593Smuzhiyun retval = len;
170*4882a593Smuzhiyun goto out;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* do not exceed the maximum value */
174*4882a593Smuzhiyun if (buffer->cb_max_size && len > buffer->cb_max_size) {
175*4882a593Smuzhiyun retval = -EFBIG;
176*4882a593Smuzhiyun goto out;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun buffer->bin_buffer = vmalloc(len);
180*4882a593Smuzhiyun if (buffer->bin_buffer == NULL) {
181*4882a593Smuzhiyun retval = -ENOMEM;
182*4882a593Smuzhiyun goto out;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun buffer->bin_buffer_size = len;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* perform second read to fill buffer */
187*4882a593Smuzhiyun down_read(&frag->frag_sem);
188*4882a593Smuzhiyun if (!frag->frag_dead)
189*4882a593Smuzhiyun len = buffer->bin_attr->read(buffer->item,
190*4882a593Smuzhiyun buffer->bin_buffer, len);
191*4882a593Smuzhiyun else
192*4882a593Smuzhiyun len = -ENOENT;
193*4882a593Smuzhiyun up_read(&frag->frag_sem);
194*4882a593Smuzhiyun if (len < 0) {
195*4882a593Smuzhiyun retval = len;
196*4882a593Smuzhiyun vfree(buffer->bin_buffer);
197*4882a593Smuzhiyun buffer->bin_buffer_size = 0;
198*4882a593Smuzhiyun buffer->bin_buffer = NULL;
199*4882a593Smuzhiyun goto out;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun buffer->needs_read_fill = 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun retval = simple_read_from_buffer(buf, count, ppos, buffer->bin_buffer,
206*4882a593Smuzhiyun buffer->bin_buffer_size);
207*4882a593Smuzhiyun out:
208*4882a593Smuzhiyun mutex_unlock(&buffer->mutex);
209*4882a593Smuzhiyun return retval;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /**
214*4882a593Smuzhiyun * fill_write_buffer - copy buffer from userspace.
215*4882a593Smuzhiyun * @buffer: data buffer for file.
216*4882a593Smuzhiyun * @buf: data from user.
217*4882a593Smuzhiyun * @count: number of bytes in @userbuf.
218*4882a593Smuzhiyun *
219*4882a593Smuzhiyun * Allocate @buffer->page if it hasn't been already, then
220*4882a593Smuzhiyun * copy the user-supplied buffer into it.
221*4882a593Smuzhiyun */
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun static int
fill_write_buffer(struct configfs_buffer * buffer,const char __user * buf,size_t count)224*4882a593Smuzhiyun fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size_t count)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun int error;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (!buffer->page)
229*4882a593Smuzhiyun buffer->page = (char *)__get_free_pages(GFP_KERNEL, 0);
230*4882a593Smuzhiyun if (!buffer->page)
231*4882a593Smuzhiyun return -ENOMEM;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (count >= SIMPLE_ATTR_SIZE)
234*4882a593Smuzhiyun count = SIMPLE_ATTR_SIZE - 1;
235*4882a593Smuzhiyun error = copy_from_user(buffer->page,buf,count);
236*4882a593Smuzhiyun buffer->needs_read_fill = 1;
237*4882a593Smuzhiyun /* if buf is assumed to contain a string, terminate it by \0,
238*4882a593Smuzhiyun * so e.g. sscanf() can scan the string easily */
239*4882a593Smuzhiyun buffer->page[count] = 0;
240*4882a593Smuzhiyun return error ? -EFAULT : count;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun static int
flush_write_buffer(struct file * file,struct configfs_buffer * buffer,size_t count)244*4882a593Smuzhiyun flush_write_buffer(struct file *file, struct configfs_buffer *buffer, size_t count)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct configfs_fragment *frag = to_frag(file);
247*4882a593Smuzhiyun int res = -ENOENT;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun down_read(&frag->frag_sem);
250*4882a593Smuzhiyun if (!frag->frag_dead)
251*4882a593Smuzhiyun res = buffer->attr->store(buffer->item, buffer->page, count);
252*4882a593Smuzhiyun up_read(&frag->frag_sem);
253*4882a593Smuzhiyun return res;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /**
258*4882a593Smuzhiyun * configfs_write_file - write an attribute.
259*4882a593Smuzhiyun * @file: file pointer
260*4882a593Smuzhiyun * @buf: data to write
261*4882a593Smuzhiyun * @count: number of bytes
262*4882a593Smuzhiyun * @ppos: starting offset
263*4882a593Smuzhiyun *
264*4882a593Smuzhiyun * Similar to configfs_read_file(), though working in the opposite direction.
265*4882a593Smuzhiyun * We allocate and fill the data from the user in fill_write_buffer(),
266*4882a593Smuzhiyun * then push it to the config_item in flush_write_buffer().
267*4882a593Smuzhiyun * There is no easy way for us to know if userspace is only doing a partial
268*4882a593Smuzhiyun * write, so we don't support them. We expect the entire buffer to come
269*4882a593Smuzhiyun * on the first write.
270*4882a593Smuzhiyun * Hint: if you're writing a value, first read the file, modify only
271*4882a593Smuzhiyun * the value you're changing, then write entire buffer back.
272*4882a593Smuzhiyun */
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun static ssize_t
configfs_write_file(struct file * file,const char __user * buf,size_t count,loff_t * ppos)275*4882a593Smuzhiyun configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct configfs_buffer *buffer = file->private_data;
278*4882a593Smuzhiyun ssize_t len;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun mutex_lock(&buffer->mutex);
281*4882a593Smuzhiyun len = fill_write_buffer(buffer, buf, count);
282*4882a593Smuzhiyun if (len > 0)
283*4882a593Smuzhiyun len = flush_write_buffer(file, buffer, len);
284*4882a593Smuzhiyun if (len > 0)
285*4882a593Smuzhiyun *ppos += len;
286*4882a593Smuzhiyun mutex_unlock(&buffer->mutex);
287*4882a593Smuzhiyun return len;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /**
291*4882a593Smuzhiyun * configfs_write_bin_file - write a binary attribute.
292*4882a593Smuzhiyun * @file: file pointer
293*4882a593Smuzhiyun * @buf: data to write
294*4882a593Smuzhiyun * @count: number of bytes
295*4882a593Smuzhiyun * @ppos: starting offset
296*4882a593Smuzhiyun *
297*4882a593Smuzhiyun * Writing to a binary attribute file is similar to a normal read.
298*4882a593Smuzhiyun * We buffer the consecutive writes (binary attribute files do not
299*4882a593Smuzhiyun * support lseek) in a continuously growing buffer, but we don't
300*4882a593Smuzhiyun * commit until the close of the file.
301*4882a593Smuzhiyun */
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun static ssize_t
configfs_write_bin_file(struct file * file,const char __user * buf,size_t count,loff_t * ppos)304*4882a593Smuzhiyun configfs_write_bin_file(struct file *file, const char __user *buf,
305*4882a593Smuzhiyun size_t count, loff_t *ppos)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun struct configfs_buffer *buffer = file->private_data;
308*4882a593Smuzhiyun void *tbuf = NULL;
309*4882a593Smuzhiyun ssize_t len;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun mutex_lock(&buffer->mutex);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /* we don't support switching read/write modes */
314*4882a593Smuzhiyun if (buffer->read_in_progress) {
315*4882a593Smuzhiyun len = -ETXTBSY;
316*4882a593Smuzhiyun goto out;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun buffer->write_in_progress = true;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /* buffer grows? */
321*4882a593Smuzhiyun if (*ppos + count > buffer->bin_buffer_size) {
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun if (buffer->cb_max_size &&
324*4882a593Smuzhiyun *ppos + count > buffer->cb_max_size) {
325*4882a593Smuzhiyun len = -EFBIG;
326*4882a593Smuzhiyun goto out;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun tbuf = vmalloc(*ppos + count);
330*4882a593Smuzhiyun if (tbuf == NULL) {
331*4882a593Smuzhiyun len = -ENOMEM;
332*4882a593Smuzhiyun goto out;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* copy old contents */
336*4882a593Smuzhiyun if (buffer->bin_buffer) {
337*4882a593Smuzhiyun memcpy(tbuf, buffer->bin_buffer,
338*4882a593Smuzhiyun buffer->bin_buffer_size);
339*4882a593Smuzhiyun vfree(buffer->bin_buffer);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun /* clear the new area */
343*4882a593Smuzhiyun memset(tbuf + buffer->bin_buffer_size, 0,
344*4882a593Smuzhiyun *ppos + count - buffer->bin_buffer_size);
345*4882a593Smuzhiyun buffer->bin_buffer = tbuf;
346*4882a593Smuzhiyun buffer->bin_buffer_size = *ppos + count;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun len = simple_write_to_buffer(buffer->bin_buffer,
350*4882a593Smuzhiyun buffer->bin_buffer_size, ppos, buf, count);
351*4882a593Smuzhiyun out:
352*4882a593Smuzhiyun mutex_unlock(&buffer->mutex);
353*4882a593Smuzhiyun return len;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
__configfs_open_file(struct inode * inode,struct file * file,int type)356*4882a593Smuzhiyun static int __configfs_open_file(struct inode *inode, struct file *file, int type)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun struct dentry *dentry = file->f_path.dentry;
359*4882a593Smuzhiyun struct configfs_fragment *frag = to_frag(file);
360*4882a593Smuzhiyun struct configfs_attribute *attr;
361*4882a593Smuzhiyun struct configfs_buffer *buffer;
362*4882a593Smuzhiyun int error;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun error = -ENOMEM;
365*4882a593Smuzhiyun buffer = kzalloc(sizeof(struct configfs_buffer), GFP_KERNEL);
366*4882a593Smuzhiyun if (!buffer)
367*4882a593Smuzhiyun goto out;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun error = -ENOENT;
370*4882a593Smuzhiyun down_read(&frag->frag_sem);
371*4882a593Smuzhiyun if (unlikely(frag->frag_dead))
372*4882a593Smuzhiyun goto out_free_buffer;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun error = -EINVAL;
375*4882a593Smuzhiyun buffer->item = to_item(dentry->d_parent);
376*4882a593Smuzhiyun if (!buffer->item)
377*4882a593Smuzhiyun goto out_free_buffer;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun attr = to_attr(dentry);
380*4882a593Smuzhiyun if (!attr)
381*4882a593Smuzhiyun goto out_free_buffer;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (type & CONFIGFS_ITEM_BIN_ATTR) {
384*4882a593Smuzhiyun buffer->bin_attr = to_bin_attr(dentry);
385*4882a593Smuzhiyun buffer->cb_max_size = buffer->bin_attr->cb_max_size;
386*4882a593Smuzhiyun } else {
387*4882a593Smuzhiyun buffer->attr = attr;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun buffer->owner = attr->ca_owner;
391*4882a593Smuzhiyun /* Grab the module reference for this attribute if we have one */
392*4882a593Smuzhiyun error = -ENODEV;
393*4882a593Smuzhiyun if (!try_module_get(buffer->owner))
394*4882a593Smuzhiyun goto out_free_buffer;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun error = -EACCES;
397*4882a593Smuzhiyun if (!buffer->item->ci_type)
398*4882a593Smuzhiyun goto out_put_module;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun buffer->ops = buffer->item->ci_type->ct_item_ops;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun /* File needs write support.
403*4882a593Smuzhiyun * The inode's perms must say it's ok,
404*4882a593Smuzhiyun * and we must have a store method.
405*4882a593Smuzhiyun */
406*4882a593Smuzhiyun if (file->f_mode & FMODE_WRITE) {
407*4882a593Smuzhiyun if (!(inode->i_mode & S_IWUGO))
408*4882a593Smuzhiyun goto out_put_module;
409*4882a593Smuzhiyun if ((type & CONFIGFS_ITEM_ATTR) && !attr->store)
410*4882a593Smuzhiyun goto out_put_module;
411*4882a593Smuzhiyun if ((type & CONFIGFS_ITEM_BIN_ATTR) && !buffer->bin_attr->write)
412*4882a593Smuzhiyun goto out_put_module;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /* File needs read support.
416*4882a593Smuzhiyun * The inode's perms must say it's ok, and we there
417*4882a593Smuzhiyun * must be a show method for it.
418*4882a593Smuzhiyun */
419*4882a593Smuzhiyun if (file->f_mode & FMODE_READ) {
420*4882a593Smuzhiyun if (!(inode->i_mode & S_IRUGO))
421*4882a593Smuzhiyun goto out_put_module;
422*4882a593Smuzhiyun if ((type & CONFIGFS_ITEM_ATTR) && !attr->show)
423*4882a593Smuzhiyun goto out_put_module;
424*4882a593Smuzhiyun if ((type & CONFIGFS_ITEM_BIN_ATTR) && !buffer->bin_attr->read)
425*4882a593Smuzhiyun goto out_put_module;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun mutex_init(&buffer->mutex);
429*4882a593Smuzhiyun buffer->needs_read_fill = 1;
430*4882a593Smuzhiyun buffer->read_in_progress = false;
431*4882a593Smuzhiyun buffer->write_in_progress = false;
432*4882a593Smuzhiyun file->private_data = buffer;
433*4882a593Smuzhiyun up_read(&frag->frag_sem);
434*4882a593Smuzhiyun return 0;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun out_put_module:
437*4882a593Smuzhiyun module_put(buffer->owner);
438*4882a593Smuzhiyun out_free_buffer:
439*4882a593Smuzhiyun up_read(&frag->frag_sem);
440*4882a593Smuzhiyun kfree(buffer);
441*4882a593Smuzhiyun out:
442*4882a593Smuzhiyun return error;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
configfs_release(struct inode * inode,struct file * filp)445*4882a593Smuzhiyun static int configfs_release(struct inode *inode, struct file *filp)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun struct configfs_buffer *buffer = filp->private_data;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun module_put(buffer->owner);
450*4882a593Smuzhiyun if (buffer->page)
451*4882a593Smuzhiyun free_page((unsigned long)buffer->page);
452*4882a593Smuzhiyun mutex_destroy(&buffer->mutex);
453*4882a593Smuzhiyun kfree(buffer);
454*4882a593Smuzhiyun return 0;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
configfs_open_file(struct inode * inode,struct file * filp)457*4882a593Smuzhiyun static int configfs_open_file(struct inode *inode, struct file *filp)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun return __configfs_open_file(inode, filp, CONFIGFS_ITEM_ATTR);
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
configfs_open_bin_file(struct inode * inode,struct file * filp)462*4882a593Smuzhiyun static int configfs_open_bin_file(struct inode *inode, struct file *filp)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun return __configfs_open_file(inode, filp, CONFIGFS_ITEM_BIN_ATTR);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
configfs_release_bin_file(struct inode * inode,struct file * file)467*4882a593Smuzhiyun static int configfs_release_bin_file(struct inode *inode, struct file *file)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun struct configfs_buffer *buffer = file->private_data;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun buffer->read_in_progress = false;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (buffer->write_in_progress) {
474*4882a593Smuzhiyun struct configfs_fragment *frag = to_frag(file);
475*4882a593Smuzhiyun buffer->write_in_progress = false;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun down_read(&frag->frag_sem);
478*4882a593Smuzhiyun if (!frag->frag_dead) {
479*4882a593Smuzhiyun /* result of ->release() is ignored */
480*4882a593Smuzhiyun buffer->bin_attr->write(buffer->item,
481*4882a593Smuzhiyun buffer->bin_buffer,
482*4882a593Smuzhiyun buffer->bin_buffer_size);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun up_read(&frag->frag_sem);
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun vfree(buffer->bin_buffer);
488*4882a593Smuzhiyun buffer->bin_buffer = NULL;
489*4882a593Smuzhiyun buffer->bin_buffer_size = 0;
490*4882a593Smuzhiyun buffer->needs_read_fill = 1;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun configfs_release(inode, file);
493*4882a593Smuzhiyun return 0;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun const struct file_operations configfs_file_operations = {
498*4882a593Smuzhiyun .read = configfs_read_file,
499*4882a593Smuzhiyun .write = configfs_write_file,
500*4882a593Smuzhiyun .llseek = generic_file_llseek,
501*4882a593Smuzhiyun .open = configfs_open_file,
502*4882a593Smuzhiyun .release = configfs_release,
503*4882a593Smuzhiyun };
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun const struct file_operations configfs_bin_file_operations = {
506*4882a593Smuzhiyun .read = configfs_read_bin_file,
507*4882a593Smuzhiyun .write = configfs_write_bin_file,
508*4882a593Smuzhiyun .llseek = NULL, /* bin file is not seekable */
509*4882a593Smuzhiyun .open = configfs_open_bin_file,
510*4882a593Smuzhiyun .release = configfs_release_bin_file,
511*4882a593Smuzhiyun };
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /**
514*4882a593Smuzhiyun * configfs_create_file - create an attribute file for an item.
515*4882a593Smuzhiyun * @item: item we're creating for.
516*4882a593Smuzhiyun * @attr: atrribute descriptor.
517*4882a593Smuzhiyun */
518*4882a593Smuzhiyun
configfs_create_file(struct config_item * item,const struct configfs_attribute * attr)519*4882a593Smuzhiyun int configfs_create_file(struct config_item * item, const struct configfs_attribute * attr)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun struct dentry *dir = item->ci_dentry;
522*4882a593Smuzhiyun struct configfs_dirent *parent_sd = dir->d_fsdata;
523*4882a593Smuzhiyun umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
524*4882a593Smuzhiyun int error = 0;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun inode_lock_nested(d_inode(dir), I_MUTEX_NORMAL);
527*4882a593Smuzhiyun error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode,
528*4882a593Smuzhiyun CONFIGFS_ITEM_ATTR, parent_sd->s_frag);
529*4882a593Smuzhiyun inode_unlock(d_inode(dir));
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun return error;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /**
535*4882a593Smuzhiyun * configfs_create_bin_file - create a binary attribute file for an item.
536*4882a593Smuzhiyun * @item: item we're creating for.
537*4882a593Smuzhiyun * @attr: atrribute descriptor.
538*4882a593Smuzhiyun */
539*4882a593Smuzhiyun
configfs_create_bin_file(struct config_item * item,const struct configfs_bin_attribute * bin_attr)540*4882a593Smuzhiyun int configfs_create_bin_file(struct config_item *item,
541*4882a593Smuzhiyun const struct configfs_bin_attribute *bin_attr)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun struct dentry *dir = item->ci_dentry;
544*4882a593Smuzhiyun struct configfs_dirent *parent_sd = dir->d_fsdata;
545*4882a593Smuzhiyun umode_t mode = (bin_attr->cb_attr.ca_mode & S_IALLUGO) | S_IFREG;
546*4882a593Smuzhiyun int error = 0;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun inode_lock_nested(dir->d_inode, I_MUTEX_NORMAL);
549*4882a593Smuzhiyun error = configfs_make_dirent(parent_sd, NULL, (void *) bin_attr, mode,
550*4882a593Smuzhiyun CONFIGFS_ITEM_BIN_ATTR, parent_sd->s_frag);
551*4882a593Smuzhiyun inode_unlock(dir->d_inode);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun return error;
554*4882a593Smuzhiyun }
555