xref: /third_party/NuttX/fs/driver/fs_blockproxy.c (revision beacf11b)
1beacf11bSopenharmony_ci/****************************************************************************
2beacf11bSopenharmony_ci * fs/driver/fs_blockproxy.c
3beacf11bSopenharmony_ci *
4beacf11bSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5beacf11bSopenharmony_ci * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/)
6beacf11bSopenharmony_ci *
7beacf11bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8beacf11bSopenharmony_ci * you may not use this file except in compliance with the License.
9beacf11bSopenharmony_ci * You may obtain a copy of the License at
10beacf11bSopenharmony_ci *
11beacf11bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
12beacf11bSopenharmony_ci *
13beacf11bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14beacf11bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15beacf11bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16beacf11bSopenharmony_ci * See the License for the specific language governing permissions and
17beacf11bSopenharmony_ci * limitations under the License.
18beacf11bSopenharmony_ci *
19beacf11bSopenharmony_ci ****************************************************************************/
20beacf11bSopenharmony_ci
21beacf11bSopenharmony_ci/****************************************************************************
22beacf11bSopenharmony_ci * Included Files
23beacf11bSopenharmony_ci ****************************************************************************/
24beacf11bSopenharmony_ci
25beacf11bSopenharmony_ci#include <sys/types.h>
26beacf11bSopenharmony_ci#include <sys/stat.h>
27beacf11bSopenharmony_ci#include <stdlib.h>
28beacf11bSopenharmony_ci#include <unistd.h>
29beacf11bSopenharmony_ci#include <stdio.h>
30beacf11bSopenharmony_ci#include <fcntl.h>
31beacf11bSopenharmony_ci#include <semaphore.h>
32beacf11bSopenharmony_ci#include <string.h>
33beacf11bSopenharmony_ci#include <errno.h>
34beacf11bSopenharmony_ci#include <assert.h>
35beacf11bSopenharmony_ci#include "fs/driver.h"
36beacf11bSopenharmony_ci#include "blockproxy.h"
37beacf11bSopenharmony_ci
38beacf11bSopenharmony_ci#ifdef LOSCFG_FS_VFS_BLOCK_DEVICE
39beacf11bSopenharmony_ci
40beacf11bSopenharmony_ci/****************************************************************************
41beacf11bSopenharmony_ci * Private Data
42beacf11bSopenharmony_ci ****************************************************************************/
43beacf11bSopenharmony_ci
44beacf11bSopenharmony_cistatic uint32_t g_devno;
45beacf11bSopenharmony_cistatic sem_t g_devno_sem;
46beacf11bSopenharmony_ci
47beacf11bSopenharmony_ci/****************************************************************************
48beacf11bSopenharmony_ci * Private Functions
49beacf11bSopenharmony_ci ****************************************************************************/
50beacf11bSopenharmony_ci
51beacf11bSopenharmony_ci/****************************************************************************
52beacf11bSopenharmony_ci * Name: unique_chardev
53beacf11bSopenharmony_ci *
54beacf11bSopenharmony_ci * Description:
55beacf11bSopenharmony_ci *   Create a unique temporary device name in the /dev/ directory of the
56beacf11bSopenharmony_ci *   pseudo-file system.  We cannot use mktemp for this because it will
57beacf11bSopenharmony_ci *   attempt to open() the file.
58beacf11bSopenharmony_ci *
59beacf11bSopenharmony_ci * Input Parameters:
60beacf11bSopenharmony_ci *   None
61beacf11bSopenharmony_ci *
62beacf11bSopenharmony_ci * Returned Value:
63beacf11bSopenharmony_ci *   The allocated path to the device.  This must be released by the caller
64beacf11bSopenharmony_ci *   to prevent memory links.  NULL will be returned only the case where
65beacf11bSopenharmony_ci *   we fail to allocate memory.
66beacf11bSopenharmony_ci *
67beacf11bSopenharmony_ci ****************************************************************************/
68beacf11bSopenharmony_ci
69beacf11bSopenharmony_cistatic char *unique_chardev(void)
70beacf11bSopenharmony_ci{
71beacf11bSopenharmony_ci  struct stat statbuf;
72beacf11bSopenharmony_ci  char devbuf[16];
73beacf11bSopenharmony_ci  uint32_t devno;
74beacf11bSopenharmony_ci  int ret;
75beacf11bSopenharmony_ci
76beacf11bSopenharmony_ci  /* Loop until we get a unique device name */
77beacf11bSopenharmony_ci
78beacf11bSopenharmony_ci  for (; ;)
79beacf11bSopenharmony_ci    {
80beacf11bSopenharmony_ci      /* Get the semaphore protecting the path number */
81beacf11bSopenharmony_ci
82beacf11bSopenharmony_ci      while (sem_wait(&g_devno_sem) != 0)
83beacf11bSopenharmony_ci        {
84beacf11bSopenharmony_ci          /* The only case that an error should occur here is if the wait
85beacf11bSopenharmony_ci           * was awakened by a signal.
86beacf11bSopenharmony_ci           */
87beacf11bSopenharmony_ci
88beacf11bSopenharmony_ci          ret = get_errno();
89beacf11bSopenharmony_ci          LOS_ASSERT(ret == EINTR);
90beacf11bSopenharmony_ci        }
91beacf11bSopenharmony_ci
92beacf11bSopenharmony_ci      /* Get the next device number and release the semaphore */
93beacf11bSopenharmony_ci
94beacf11bSopenharmony_ci      devno = ++g_devno;
95beacf11bSopenharmony_ci      (void)sem_post(&g_devno_sem);
96beacf11bSopenharmony_ci
97beacf11bSopenharmony_ci      /* Construct the full device number */
98beacf11bSopenharmony_ci
99beacf11bSopenharmony_ci      devno &= 0xffffff;
100beacf11bSopenharmony_ci      ret = snprintf_s(devbuf, 16, 14, "/dev/tmp%06lx", (unsigned long)devno);
101beacf11bSopenharmony_ci      /* length of the format string is 14 */
102beacf11bSopenharmony_ci      if (ret < 0)
103beacf11bSopenharmony_ci        {
104beacf11bSopenharmony_ci          set_errno(ENAMETOOLONG);
105beacf11bSopenharmony_ci          return strdup(devbuf);
106beacf11bSopenharmony_ci        }
107beacf11bSopenharmony_ci
108beacf11bSopenharmony_ci      /* Make sure that file name is not in use */
109beacf11bSopenharmony_ci
110beacf11bSopenharmony_ci      ret = stat(devbuf, &statbuf);
111beacf11bSopenharmony_ci      if (ret < 0)
112beacf11bSopenharmony_ci        {
113beacf11bSopenharmony_ci          DEBUGASSERT(errno == ENOENT);
114beacf11bSopenharmony_ci          return strdup(devbuf);
115beacf11bSopenharmony_ci        }
116beacf11bSopenharmony_ci
117beacf11bSopenharmony_ci      /* It is in use, try again */
118beacf11bSopenharmony_ci    }
119beacf11bSopenharmony_ci}
120beacf11bSopenharmony_ci
121beacf11bSopenharmony_ci/****************************************************************************
122beacf11bSopenharmony_ci * Public Functions
123beacf11bSopenharmony_ci ****************************************************************************/
124beacf11bSopenharmony_ci
125beacf11bSopenharmony_ci/****************************************************************************
126beacf11bSopenharmony_ci * Name: block_proxy
127beacf11bSopenharmony_ci *
128beacf11bSopenharmony_ci * Description:
129beacf11bSopenharmony_ci *   Create a temporary char driver using drivers/bch to mediate character
130beacf11bSopenharmony_ci *   oriented accessed to the block driver.
131beacf11bSopenharmony_ci *
132beacf11bSopenharmony_ci * Input Parameters:
133beacf11bSopenharmony_ci *   blkdev - The path to the block driver
134beacf11bSopenharmony_ci *   oflags - Character driver open flags
135beacf11bSopenharmony_ci *
136beacf11bSopenharmony_ci * Returned Value:
137beacf11bSopenharmony_ci *   If positive, non-zero file descriptor is returned on success.  This
138beacf11bSopenharmony_ci *   is the file descriptor of the nameless character driver that mediates
139beacf11bSopenharmony_ci *   accesses to the block driver.
140beacf11bSopenharmony_ci *
141beacf11bSopenharmony_ci *   Errors that may be returned:
142beacf11bSopenharmony_ci *
143beacf11bSopenharmony_ci *     ENOMEM - Failed to create a temporay path name.
144beacf11bSopenharmony_ci *
145beacf11bSopenharmony_ci *   Plus:
146beacf11bSopenharmony_ci *
147beacf11bSopenharmony_ci *     - Errors reported from bchdev_register()
148beacf11bSopenharmony_ci *     - Errors reported from open() or unlink()
149beacf11bSopenharmony_ci *
150beacf11bSopenharmony_ci ****************************************************************************/
151beacf11bSopenharmony_ci
152beacf11bSopenharmony_ciint block_proxy(const char *blkdev, int oflags)
153beacf11bSopenharmony_ci{
154beacf11bSopenharmony_ci  struct file *filep = NULL;
155beacf11bSopenharmony_ci  struct Vnode *vnode = NULL;
156beacf11bSopenharmony_ci  char *chardev;
157beacf11bSopenharmony_ci  bool readonly;
158beacf11bSopenharmony_ci  int ret;
159beacf11bSopenharmony_ci  int fd;
160beacf11bSopenharmony_ci
161beacf11bSopenharmony_ci  DEBUGASSERT(blkdev);
162beacf11bSopenharmony_ci  (void)sem_init(&g_devno_sem, 0, 1);
163beacf11bSopenharmony_ci
164beacf11bSopenharmony_ci  /* Create a unique temporary file name for the character device */
165beacf11bSopenharmony_ci
166beacf11bSopenharmony_ci  chardev = unique_chardev();
167beacf11bSopenharmony_ci  if (chardev == NULL)
168beacf11bSopenharmony_ci    {
169beacf11bSopenharmony_ci      PRINTK("ERROR: Failed to create temporary device name\n");
170beacf11bSopenharmony_ci      (void)sem_destroy(&g_devno_sem);
171beacf11bSopenharmony_ci      return -ENOMEM;
172beacf11bSopenharmony_ci    }
173beacf11bSopenharmony_ci
174beacf11bSopenharmony_ci  /* Should this character driver be read-only? */
175beacf11bSopenharmony_ci
176beacf11bSopenharmony_ci  readonly = (((unsigned int)oflags & O_ACCMODE) == O_RDONLY);
177beacf11bSopenharmony_ci
178beacf11bSopenharmony_ci  /* Wrap the block driver with an instance of the BCH driver */
179beacf11bSopenharmony_ci
180beacf11bSopenharmony_ci  ret = bchdev_register(blkdev, chardev, readonly);
181beacf11bSopenharmony_ci  if (ret < 0)
182beacf11bSopenharmony_ci    {
183beacf11bSopenharmony_ci      PRINTK("ERROR: bchdev_register(%s, %s) failed: %d\n", blkdev, chardev, ret);
184beacf11bSopenharmony_ci      goto errout_with_chardev;
185beacf11bSopenharmony_ci    }
186beacf11bSopenharmony_ci
187beacf11bSopenharmony_ci  /* Open the newly created character driver */
188beacf11bSopenharmony_ci
189beacf11bSopenharmony_ci  oflags =(unsigned int)oflags & (~(O_CREAT | O_EXCL | O_APPEND | O_TRUNC));
190beacf11bSopenharmony_ci  fd = open(chardev, oflags);
191beacf11bSopenharmony_ci  if (fd < 0)
192beacf11bSopenharmony_ci    {
193beacf11bSopenharmony_ci      ret = -errno;
194beacf11bSopenharmony_ci      PRINTK("ERROR: Failed to open %s: %d\n", chardev, ret);
195beacf11bSopenharmony_ci      goto errout_with_bchdev;
196beacf11bSopenharmony_ci    }
197beacf11bSopenharmony_ci
198beacf11bSopenharmony_ci  ret = fs_getfilep(fd, &filep);
199beacf11bSopenharmony_ci  if (ret < 0)
200beacf11bSopenharmony_ci    {
201beacf11bSopenharmony_ci      files_release(fd);
202beacf11bSopenharmony_ci      ret = -get_errno();
203beacf11bSopenharmony_ci      goto errout_with_bchdev;
204beacf11bSopenharmony_ci    }
205beacf11bSopenharmony_ci
206beacf11bSopenharmony_ci  vnode = filep->f_vnode;
207beacf11bSopenharmony_ci  VnodeHold();
208beacf11bSopenharmony_ci  vnode->type = VNODE_TYPE_BCHR;
209beacf11bSopenharmony_ci  VnodeDrop();
210beacf11bSopenharmony_ci
211beacf11bSopenharmony_ci  /* Free the allocate character driver name and return the open file
212beacf11bSopenharmony_ci   * descriptor.
213beacf11bSopenharmony_ci   */
214beacf11bSopenharmony_ci
215beacf11bSopenharmony_ci  (void)free(chardev);
216beacf11bSopenharmony_ci  (void)sem_destroy(&g_devno_sem);
217beacf11bSopenharmony_ci  return fd;
218beacf11bSopenharmony_ci
219beacf11bSopenharmony_cierrout_with_bchdev:
220beacf11bSopenharmony_ci  (void)unregister_driver(chardev);
221beacf11bSopenharmony_cierrout_with_chardev:
222beacf11bSopenharmony_ci  (void)free(chardev);
223beacf11bSopenharmony_ci  (void)sem_destroy(&g_devno_sem);
224beacf11bSopenharmony_ci  return ret;
225beacf11bSopenharmony_ci}
226beacf11bSopenharmony_ci
227beacf11bSopenharmony_ci#endif
228