• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/driver/fs_blockproxy.c
3  *
4  *   Copyright (C) 2015-2018 Gregory Nutt. All rights reserved.
5  *   Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name NuttX nor the names of its contributors may be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************/
35 
36 /****************************************************************************
37  * Included Files
38  ****************************************************************************/
39 
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <fcntl.h>
46 #include <semaphore.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <assert.h>
50 #include "fs/driver.h"
51 #include "blockproxy.h"
52 
53 #ifdef LOSCFG_FS_VFS_BLOCK_DEVICE
54 
55 /****************************************************************************
56  * Private Data
57  ****************************************************************************/
58 
59 static uint32_t g_devno;
60 static sem_t g_devno_sem;
61 
62 /****************************************************************************
63  * Private Functions
64  ****************************************************************************/
65 
66 /****************************************************************************
67  * Name: unique_chardev
68  *
69  * Description:
70  *   Create a unique temporary device name in the /dev/ directory of the
71  *   pseudo-file system.  We cannot use mktemp for this because it will
72  *   attempt to open() the file.
73  *
74  * Input Parameters:
75  *   None
76  *
77  * Returned Value:
78  *   The allocated path to the device.  This must be released by the caller
79  *   to prevent memory links.  NULL will be returned only the case where
80  *   we fail to allocate memory.
81  *
82  ****************************************************************************/
83 
unique_chardev(void)84 static char *unique_chardev(void)
85 {
86   struct stat statbuf;
87   char devbuf[16];
88   uint32_t devno;
89   int ret;
90 
91   /* Loop until we get a unique device name */
92 
93   for (; ;)
94     {
95       /* Get the semaphore protecting the path number */
96 
97       while (sem_wait(&g_devno_sem) != 0)
98         {
99           /* The only case that an error should occur here is if the wait
100            * was awakened by a signal.
101            */
102 
103           ret = get_errno();
104           LOS_ASSERT(ret == EINTR);
105         }
106 
107       /* Get the next device number and release the semaphore */
108 
109       devno = ++g_devno;
110       (void)sem_post(&g_devno_sem);
111 
112       /* Construct the full device number */
113 
114       devno &= 0xffffff;
115       ret = snprintf_s(devbuf, 16, 14, "/dev/tmp%06lx", (unsigned long)devno);
116       /* length of the format string is 14 */
117       if (ret < 0)
118         {
119           set_errno(ENAMETOOLONG);
120           return strdup(devbuf);
121         }
122 
123       /* Make sure that file name is not in use */
124 
125       ret = stat(devbuf, &statbuf);
126       if (ret < 0)
127         {
128           DEBUGASSERT(errno == ENOENT);
129           return strdup(devbuf);
130         }
131 
132       /* It is in use, try again */
133     }
134 }
135 
136 /****************************************************************************
137  * Public Functions
138  ****************************************************************************/
139 
140 /****************************************************************************
141  * Name: block_proxy
142  *
143  * Description:
144  *   Create a temporary char driver using drivers/bch to mediate character
145  *   oriented accessed to the block driver.
146  *
147  * Input Parameters:
148  *   blkdev - The path to the block driver
149  *   oflags - Character driver open flags
150  *
151  * Returned Value:
152  *   If positive, non-zero file descriptor is returned on success.  This
153  *   is the file descriptor of the nameless character driver that mediates
154  *   accesses to the block driver.
155  *
156  *   Errors that may be returned:
157  *
158  *     ENOMEM - Failed to create a temporay path name.
159  *
160  *   Plus:
161  *
162  *     - Errors reported from bchdev_register()
163  *     - Errors reported from open() or unlink()
164  *
165  ****************************************************************************/
166 
block_proxy(const char * blkdev,int oflags)167 int block_proxy(const char *blkdev, int oflags)
168 {
169   struct file *filep = NULL;
170   struct Vnode *vnode = NULL;
171   char *chardev;
172   bool readonly;
173   int ret;
174   int fd;
175 
176   DEBUGASSERT(blkdev);
177   (void)sem_init(&g_devno_sem, 0, 1);
178 
179   /* Create a unique temporary file name for the character device */
180 
181   chardev = unique_chardev();
182   if (chardev == NULL)
183     {
184       PRINTK("ERROR: Failed to create temporary device name\n");
185       (void)sem_destroy(&g_devno_sem);
186       return -ENOMEM;
187     }
188 
189   /* Should this character driver be read-only? */
190 
191   readonly = (((unsigned int)oflags & O_ACCMODE) == O_RDONLY);
192 
193   /* Wrap the block driver with an instance of the BCH driver */
194 
195   ret = bchdev_register(blkdev, chardev, readonly);
196   if (ret < 0)
197     {
198       PRINTK("ERROR: bchdev_register(%s, %s) failed: %d\n", blkdev, chardev, ret);
199       goto errout_with_chardev;
200     }
201 
202   /* Open the newly created character driver */
203 
204   oflags =(unsigned int)oflags & (~(O_CREAT | O_EXCL | O_APPEND | O_TRUNC));
205   fd = open(chardev, oflags);
206   if (fd < 0)
207     {
208       ret = -errno;
209       PRINTK("ERROR: Failed to open %s: %d\n", chardev, ret);
210       goto errout_with_bchdev;
211     }
212 
213   ret = fs_getfilep(fd, &filep);
214   if (ret < 0)
215     {
216       files_release(fd);
217       ret = -get_errno();
218       goto errout_with_bchdev;
219     }
220 
221   vnode = filep->f_vnode;
222   VnodeHold();
223   vnode->type = VNODE_TYPE_BCHR;
224   VnodeDrop();
225 
226   /* Free the allocate character driver name and return the open file
227    * descriptor.
228    */
229 
230   (void)free(chardev);
231   (void)sem_destroy(&g_devno_sem);
232   return fd;
233 
234 errout_with_bchdev:
235   (void)unregister_driver(chardev);
236 errout_with_chardev:
237   (void)free(chardev);
238   (void)sem_destroy(&g_devno_sem);
239   return ret;
240 }
241 
242 #endif
243