xref: /OK3568_Linux_fs/kernel/fs/configfs/file.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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