-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Usage example for merging the aaa partition and bbb partition into the merge partition: register_merge_blockdriver("/dev/merge", "/dev/aaa", "/dev/bbb", NULL) Signed-off-by: wanggang26 <[email protected]>
- Loading branch information
1 parent
6ffd007
commit e4aad73
Showing
4 changed files
with
353 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
/**************************************************************************** | ||
* fs/driver/fs_blockmerge.c | ||
* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. The | ||
* ASF licenses this file to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance with the | ||
* License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
****************************************************************************/ | ||
|
||
/**************************************************************************** | ||
* Included Files | ||
****************************************************************************/ | ||
|
||
#include <nuttx/config.h> | ||
|
||
#include <nuttx/kmalloc.h> | ||
#include <nuttx/fs/fs.h> | ||
#include <sys/param.h> | ||
#include <inttypes.h> | ||
#include <debug.h> | ||
|
||
/**************************************************************************** | ||
* Private Types | ||
****************************************************************************/ | ||
|
||
struct merge_part_s | ||
{ | ||
FAR struct inode *inode; | ||
struct geometry geo; | ||
char path[PATH_MAX]; | ||
}; | ||
|
||
struct merge_priv_s | ||
{ | ||
size_t npart; | ||
struct merge_part_s part[0]; | ||
}; | ||
|
||
/**************************************************************************** | ||
* Private Function Prototypes | ||
****************************************************************************/ | ||
|
||
static int merge_open(FAR struct inode *inode); | ||
static int merge_close(FAR struct inode *inode); | ||
static ssize_t merge_read(FAR struct inode *inode, FAR unsigned char *buffer, | ||
blkcnt_t startsector, unsigned int nsectors); | ||
static ssize_t merge_write(FAR struct inode *inode, | ||
FAR const unsigned char *buffer, | ||
blkcnt_t startsector, unsigned int nsectors); | ||
static int merge_geometry(FAR struct inode *inode, | ||
FAR struct geometry *geometry); | ||
|
||
/**************************************************************************** | ||
* Private Data | ||
****************************************************************************/ | ||
|
||
static const struct block_operations g_merge_bops = | ||
{ | ||
merge_open, /* open */ | ||
merge_close, /* close */ | ||
merge_read, /* read */ | ||
merge_write, /* write */ | ||
merge_geometry, /* geometry */ | ||
NULL /* ioctl */ | ||
}; | ||
|
||
/**************************************************************************** | ||
* Private Functions | ||
****************************************************************************/ | ||
|
||
static int merge_open(FAR struct inode *inode) | ||
{ | ||
FAR struct merge_priv_s *priv; | ||
int ret = 0; | ||
size_t i; | ||
|
||
DEBUGASSERT(inode && inode->i_private); | ||
priv = (FAR struct merge_priv_s *)inode->i_private; | ||
|
||
for (i = 0; i < priv->npart; i++) | ||
{ | ||
ret = open_blockdriver(priv->part[i].path, 0, &inode); | ||
if (ret < 0) | ||
{ | ||
ferr("ERROR: Failed to open block driver for %s\n", | ||
priv->part[i].path); | ||
goto err_with_open; | ||
} | ||
|
||
priv->part[i].inode = inode; | ||
|
||
if (inode->u.i_bops->geometry == NULL || | ||
inode->u.i_bops->geometry(inode, &priv->part[i].geo) < 0 || | ||
priv->part[i].geo.geo_sectorsize <= 0 || | ||
priv->part[i].geo.geo_nsectors <= 0) | ||
{ | ||
ferr("ERROR: Failed to get geometry for %s\n", priv->part[i].path); | ||
ret = -EINVAL; | ||
goto err_with_inode; | ||
} | ||
|
||
if (priv->part[0].geo.geo_sectorsize != | ||
priv->part[i].geo.geo_sectorsize) | ||
{ | ||
ferr("ERROR: Inconsistent sectorsize!\n"); | ||
ret = -EINVAL; | ||
goto err_with_inode; | ||
} | ||
|
||
finfo("[%s] nsectors: %" PRIuOFF " sectorsize:%u\n", | ||
priv->part[i].path, priv->part[i].geo.geo_nsectors, | ||
priv->part[i].geo.geo_sectorsize); | ||
} | ||
|
||
return ret; | ||
|
||
err_with_inode: | ||
close_blockdriver(priv->part[i].inode); | ||
err_with_open: | ||
while (i--) | ||
{ | ||
close_blockdriver(priv->part[i].inode); | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
static int merge_close(FAR struct inode *inode) | ||
{ | ||
FAR struct merge_priv_s *priv; | ||
size_t i; | ||
|
||
DEBUGASSERT(inode && inode->i_private); | ||
priv = (FAR struct merge_priv_s *)inode->i_private; | ||
|
||
for (i = 0; i < priv->npart; i++) | ||
{ | ||
int ret = close_blockdriver(priv->part[i].inode); | ||
if (ret < 0) | ||
{ | ||
ferr("ERROR: Failed to close block driver for %s\n", | ||
priv->part[i].path); | ||
return ret; | ||
} | ||
} | ||
|
||
return OK; | ||
} | ||
|
||
static ssize_t merge_read(FAR struct inode *inode, unsigned char *buffer, | ||
blkcnt_t startsector, unsigned int nsectors) | ||
{ | ||
FAR struct merge_priv_s *priv; | ||
ssize_t nread = 0; | ||
size_t ntotal = 0; | ||
size_t i; | ||
|
||
DEBUGASSERT(inode && inode->i_private); | ||
priv = (FAR struct merge_priv_s *)inode->i_private; | ||
|
||
for (i = 0; nsectors > 0 && i < priv->npart; i++) | ||
{ | ||
if ((startsector >= priv->part[i].geo.geo_nsectors)) | ||
{ | ||
startsector -= priv->part[i].geo.geo_nsectors; | ||
continue; | ||
} | ||
|
||
inode = priv->part[i].inode; | ||
nread = MIN(priv->part[i].geo.geo_nsectors - startsector, nsectors); | ||
nread = inode->u.i_bops->read(inode, buffer, startsector, nread); | ||
if (nread < 0) | ||
{ | ||
break; | ||
} | ||
|
||
buffer += nread * priv->part[i].geo.geo_sectorsize; | ||
nsectors -= nread; | ||
ntotal += nread; | ||
startsector = 0; | ||
} | ||
|
||
/* On success, return the number of blocks read */ | ||
|
||
return ntotal ? ntotal : nread; | ||
} | ||
|
||
static ssize_t merge_write(FAR struct inode *inode, | ||
const unsigned char *buffer, | ||
blkcnt_t startsector, unsigned int nsectors) | ||
{ | ||
FAR struct merge_priv_s *priv; | ||
ssize_t nwritten = 0; | ||
size_t ntotal = 0; | ||
size_t i; | ||
|
||
DEBUGASSERT(inode && inode->i_private); | ||
priv = (FAR struct merge_priv_s *)inode->i_private; | ||
|
||
for (i = 0; nsectors > 0 && i < priv->npart; i++) | ||
{ | ||
if (startsector >= priv->part[i].geo.geo_nsectors) | ||
{ | ||
startsector -= priv->part[i].geo.geo_nsectors; | ||
continue; | ||
} | ||
|
||
inode = priv->part[i].inode; | ||
nwritten = MIN(priv->part[i].geo.geo_nsectors - startsector, nsectors); | ||
nwritten = inode->u.i_bops->write(inode, buffer, startsector, | ||
nwritten); | ||
if (nwritten < 0) | ||
{ | ||
break; | ||
} | ||
|
||
buffer += nwritten * priv->part[i].geo.geo_sectorsize; | ||
nsectors -= nwritten; | ||
ntotal += nwritten; | ||
startsector = 0; | ||
} | ||
|
||
/* On success, return the number of blocks written */ | ||
|
||
return ntotal ? ntotal : nwritten; | ||
} | ||
|
||
static int merge_geometry(FAR struct inode *inode, struct geometry *geometry) | ||
{ | ||
DEBUGASSERT(inode && inode->i_private); | ||
|
||
if (geometry) | ||
{ | ||
FAR struct merge_priv_s *priv = inode->i_private; | ||
size_t i; | ||
|
||
memcpy(geometry, &priv->part[0].geo, sizeof(*geometry)); | ||
for (i = 1; i < priv->npart; i++) | ||
{ | ||
geometry->geo_nsectors += priv->part[i].geo.geo_nsectors; | ||
} | ||
|
||
finfo("nsectors: %" PRIuOFF " sectorsize:%u\n", | ||
geometry->geo_nsectors, geometry->geo_sectorsize); | ||
return OK; | ||
} | ||
|
||
return -EINVAL; | ||
} | ||
|
||
/**************************************************************************** | ||
* Public Functions | ||
****************************************************************************/ | ||
|
||
int register_merge_blockdriver(FAR const char *merge, ...) | ||
{ | ||
FAR struct merge_priv_s *priv; | ||
FAR const char *name; | ||
va_list args; | ||
size_t i; | ||
int ret; | ||
|
||
va_start(args, merge); | ||
for (i = 0; ; i++) | ||
{ | ||
name = va_arg(args, FAR const char *); | ||
if (name == NULL) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
va_end(args); | ||
|
||
if (i < 2) | ||
{ | ||
ferr("ERROR: invalid number of partitions\n"); | ||
return -EINVAL; | ||
} | ||
|
||
priv = kmm_zalloc(sizeof(struct merge_priv_s) + i * | ||
sizeof(struct merge_part_s)); | ||
if (priv == NULL) | ||
{ | ||
ferr("ERROR: out of memory\n"); | ||
return -ENOMEM; | ||
} | ||
|
||
priv->npart = i; | ||
|
||
va_start(args, merge); | ||
for (i = 0; i < priv->npart; i++) | ||
{ | ||
name = va_arg(args, FAR const char *); | ||
strlcpy(priv->part[i].path, name, PATH_MAX); | ||
} | ||
|
||
ret = register_blockdriver(merge, &g_merge_bops, 0, priv); | ||
if (ret < 0) | ||
{ | ||
ferr("ERROR: register blockdriver failed: %d\n", ret); | ||
goto err; | ||
} | ||
|
||
va_end(args); | ||
return ret; | ||
|
||
err: | ||
va_end(args); | ||
kmm_free(priv); | ||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters