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