Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
e653879c
Commit
e653879c
authored
Jan 24, 2008
by
Artem Bityutskiy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
UBI: implement atomic LEB change ioctl
Signed-off-by:
Artem Bityutskiy
<
Artem.Bityutskiy@nokia.com
>
parent
86613682
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
183 additions
and
28 deletions
+183
-28
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/cdev.c
+60
-12
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/ubi.h
+23
-4
drivers/mtd/ubi/upd.c
drivers/mtd/ubi/upd.c
+100
-12
No files found.
drivers/mtd/ubi/cdev.c
View file @
e653879c
...
...
@@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
if
(
vol
->
updating
)
{
ubi_warn
(
"update of volume %d not finished, volume is damaged"
,
vol
->
vol_id
);
ubi_assert
(
!
vol
->
changing_leb
);
vol
->
updating
=
0
;
vfree
(
vol
->
upd_buf
);
}
else
if
(
vol
->
changing_leb
)
{
dbg_msg
(
"only %lld of %lld bytes received for atomic LEB change"
" for volume %d:%d, cancel"
,
vol
->
upd_received
,
vol
->
upd_bytes
,
vol
->
ubi
->
ubi_num
,
vol
->
vol_id
);
vol
->
changing_leb
=
0
;
vfree
(
vol
->
upd_buf
);
}
ubi_close_volume
(
desc
);
...
...
@@ -351,24 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
struct
ubi_volume
*
vol
=
desc
->
vol
;
struct
ubi_device
*
ubi
=
vol
->
ubi
;
if
(
!
vol
->
updating
)
if
(
!
vol
->
updating
&&
!
vol
->
changing_leb
)
return
vol_cdev_direct_write
(
file
,
buf
,
count
,
offp
);
err
=
ubi_more_update_data
(
ubi
,
vol
,
buf
,
count
);
if
(
vol
->
updating
)
err
=
ubi_more_update_data
(
ubi
,
vol
,
buf
,
count
);
else
err
=
ubi_more_leb_change_data
(
ubi
,
vol
,
buf
,
count
);
if
(
err
<
0
)
{
ubi_err
(
"cannot
write %zd bytes of update
data, error %d"
,
ubi_err
(
"cannot
accept more %zd bytes of
data, error %d"
,
count
,
err
);
return
err
;
}
if
(
err
)
{
/*
*
Update is finished, @err contains number of actually written
*
bytes now
.
*
The operation is finished, @err contains number of actually
*
written bytes
.
*/
count
=
err
;
vol
->
updating
=
0
;
if
(
vol
->
changing_leb
)
{
revoke_exclusive
(
desc
,
UBI_READWRITE
);
return
count
;
}
err
=
ubi_check_volume
(
ubi
,
vol
->
vol_id
);
if
(
err
<
0
)
return
err
;
...
...
@@ -433,6 +448,43 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
break
;
}
/* Atomic logical eraseblock change command */
case
UBI_IOCEBCH
:
{
struct
ubi_leb_change_req
req
;
err
=
copy_from_user
(
&
req
,
argp
,
sizeof
(
struct
ubi_leb_change_req
));
if
(
err
)
{
err
=
-
EFAULT
;
break
;
}
if
(
desc
->
mode
==
UBI_READONLY
||
vol
->
vol_type
==
UBI_STATIC_VOLUME
)
{
err
=
-
EROFS
;
break
;
}
/* Validate the request */
err
=
-
EINVAL
;
if
(
req
.
lnum
<
0
||
req
.
lnum
>=
vol
->
reserved_pebs
||
req
.
bytes
<
0
||
req
.
lnum
>=
vol
->
usable_leb_size
)
break
;
if
(
req
.
dtype
!=
UBI_LONGTERM
&&
req
.
dtype
!=
UBI_SHORTTERM
&&
req
.
dtype
!=
UBI_UNKNOWN
)
break
;
err
=
get_exclusive
(
desc
);
if
(
err
<
0
)
break
;
err
=
ubi_start_leb_change
(
ubi
,
vol
,
&
req
);
if
(
req
.
bytes
==
0
)
revoke_exclusive
(
desc
,
UBI_READWRITE
);
break
;
}
#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
/* Logical eraseblock erasure command */
case
UBI_IOCEBER
:
...
...
@@ -445,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
break
;
}
if
(
desc
->
mode
==
UBI_READONLY
)
{
if
(
desc
->
mode
==
UBI_READONLY
||
vol
->
vol_type
==
UBI_STATIC_VOLUME
)
{
err
=
-
EROFS
;
break
;
}
...
...
@@ -455,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
break
;
}
if
(
vol
->
vol_type
!=
UBI_DYNAMIC_VOLUME
)
{
err
=
-
EROFS
;
break
;
}
dbg_msg
(
"erase LEB %d:%d"
,
vol
->
vol_id
,
lnum
);
err
=
ubi_eba_unmap_leb
(
ubi
,
vol
,
lnum
);
if
(
err
)
...
...
drivers/mtd/ubi/ubi.h
View file @
e653879c
...
...
@@ -158,15 +158,23 @@ struct ubi_volume_desc;
* @name: volume name
*
* @upd_ebs: how many eraseblocks are expected to be updated
* @upd_bytes: how many bytes are expected to be received
* @upd_received: how many update bytes were already received
* @upd_buf: update buffer which is used to collect update data
* @ch_lnum: LEB number which is being changing by the atomic LEB change
* operation
* @ch_dtype: data persistency type which is being changing by the atomic LEB
* change operation
* @upd_bytes: how many bytes are expected to be received for volume update or
* atomic LEB change
* @upd_received: how many bytes were already received for volume update or
* atomic LEB change
* @upd_buf: update buffer which is used to collect update data or data for
* atomic LEB change
*
* @eba_tbl: EBA table of this volume (LEB->PEB mapping)
* @checked: %1 if this static volume was checked
* @corrupted: %1 if the volume is corrupted (static volumes only)
* @upd_marker: %1 if the update marker is set for this volume
* @updating: %1 if the volume is being updated
* @changing_leb: %1 if the atomic LEB change ioctl command is in progress
*
* @gluebi_desc: gluebi UBI volume descriptor
* @gluebi_refcount: reference count of the gluebi MTD device
...
...
@@ -202,6 +210,8 @@ struct ubi_volume {
char
name
[
UBI_VOL_NAME_MAX
+
1
];
int
upd_ebs
;
int
ch_lnum
;
int
ch_dtype
;
long
long
upd_bytes
;
long
long
upd_received
;
void
*
upd_buf
;
...
...
@@ -211,9 +221,14 @@ struct ubi_volume {
int
corrupted
:
1
;
int
upd_marker
:
1
;
int
updating
:
1
;
int
changing_leb
:
1
;
#ifdef CONFIG_MTD_UBI_GLUEBI
/* Gluebi-related stuff may be compiled out */
/*
* Gluebi-related stuff may be compiled out.
* TODO: this should not be built into UBI but should be a separate
* ubimtd driver which works on top of UBI and emulates MTD devices.
*/
struct
ubi_volume_desc
*
gluebi_desc
;
int
gluebi_refcount
;
struct
mtd_info
gluebi_mtd
;
...
...
@@ -427,6 +442,10 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
long
long
bytes
);
int
ubi_more_update_data
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
const
void
__user
*
buf
,
int
count
);
int
ubi_start_leb_change
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
const
struct
ubi_leb_change_req
*
req
);
int
ubi_more_leb_change_data
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
const
void
__user
*
buf
,
int
count
);
/* misc.c */
int
ubi_calc_data_len
(
const
struct
ubi_device
*
ubi
,
const
void
*
buf
,
int
length
);
...
...
drivers/mtd/ubi/upd.c
View file @
e653879c
...
...
@@ -22,7 +22,8 @@
*/
/*
* This file contains implementation of the volume update functionality.
* This file contains implementation of the volume update and atomic LEB change
* functionality.
*
* The update operation is based on the per-volume update marker which is
* stored in the volume table. The update marker is set before the update
...
...
@@ -133,6 +134,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
uint64_t
tmp
;
dbg_msg
(
"start update of volume %d, %llu bytes"
,
vol
->
vol_id
,
bytes
);
ubi_assert
(
!
vol
->
updating
&&
!
vol
->
changing_leb
);
vol
->
updating
=
1
;
err
=
set_update_marker
(
ubi
,
vol
);
...
...
@@ -167,6 +169,39 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
return
0
;
}
/**
* ubi_start_leb_change - start atomic LEB change.
* @ubi: UBI device description object
* @vol: volume description object
* @req: operation request
*
* This function starts atomic LEB change operation. Returns zero in case of
* success and a negative error code in case of failure.
*/
int
ubi_start_leb_change
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
const
struct
ubi_leb_change_req
*
req
)
{
ubi_assert
(
!
vol
->
updating
&&
!
vol
->
changing_leb
);
dbg_msg
(
"start changing LEB %d:%d, %u bytes"
,
vol
->
vol_id
,
req
->
lnum
,
req
->
bytes
);
if
(
req
->
bytes
==
0
)
return
ubi_eba_atomic_leb_change
(
ubi
,
vol
,
req
->
lnum
,
NULL
,
0
,
req
->
dtype
);
vol
->
upd_bytes
=
req
->
bytes
;
vol
->
upd_received
=
0
;
vol
->
changing_leb
=
1
;
vol
->
ch_lnum
=
req
->
lnum
;
vol
->
ch_dtype
=
req
->
dtype
;
vol
->
upd_buf
=
vmalloc
(
req
->
bytes
);
if
(
!
vol
->
upd_buf
)
return
-
ENOMEM
;
return
0
;
}
/**
* write_leb - write update data.
* @ubi: UBI device description object
...
...
@@ -199,21 +234,19 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
static
int
write_leb
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
int
lnum
,
void
*
buf
,
int
len
,
int
used_ebs
)
{
int
err
,
l
;
int
err
;
if
(
vol
->
vol_type
==
UBI_DYNAMIC_VOLUME
)
{
l
=
ALIGN
(
len
,
ubi
->
min_io_size
);
memset
(
buf
+
len
,
0xFF
,
l
-
len
);
l
en
=
ALIGN
(
len
,
ubi
->
min_io_size
);
memset
(
buf
+
len
,
0xFF
,
l
en
-
len
);
l
=
ubi_calc_data_len
(
ubi
,
buf
,
l
);
if
(
l
==
0
)
{
l
en
=
ubi_calc_data_len
(
ubi
,
buf
,
len
);
if
(
l
en
==
0
)
{
dbg_msg
(
"all %d bytes contain 0xFF - skip"
,
len
);
return
0
;
}
if
(
len
!=
l
)
dbg_msg
(
"skip last %d bytes (0xFF)"
,
len
-
l
);
err
=
ubi_eba_write_leb
(
ubi
,
vol
,
lnum
,
buf
,
0
,
l
,
UBI_UNKNOWN
);
err
=
ubi_eba_write_leb
(
ubi
,
vol
,
lnum
,
buf
,
0
,
l
en
,
UBI_UNKNOWN
);
}
else
{
/*
* When writing static volume, and this is the last logical
...
...
@@ -239,9 +272,9 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
* @count: how much bytes to write
*
* This function writes more data to the volume which is being updated. It may
* be called arbitrary number of times until all
of the update data arrive.
*
This function returns %0 in case of success, number of bytes written during
*
the last call if the whole volume update was
successfully finished, and a
* be called arbitrary number of times until all
the update data arriveis. This
*
function returns %0 in case of success, number of bytes written during the
*
last call if the whole volume update has been
successfully finished, and a
* negative error code in case of failure.
*/
int
ubi_more_update_data
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
...
...
@@ -340,6 +373,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
return
err
;
err
=
ubi_wl_flush
(
ubi
);
if
(
err
==
0
)
{
vol
->
updating
=
0
;
err
=
to_write
;
vfree
(
vol
->
upd_buf
);
}
...
...
@@ -347,3 +381,57 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
return
err
;
}
/**
* ubi_more_leb_change_data - accept more data for atomic LEB change.
* @vol: volume description object
* @buf: write data (user-space memory buffer)
* @count: how much bytes to write
*
* This function accepts more data to the volume which is being under the
* "atomic LEB change" operation. It may be called arbitrary number of times
* until all data arrives. This function returns %0 in case of success, number
* of bytes written during the last call if the whole "atomic LEB change"
* operation has been successfully finished, and a negative error code in case
* of failure.
*/
int
ubi_more_leb_change_data
(
struct
ubi_device
*
ubi
,
struct
ubi_volume
*
vol
,
const
void
__user
*
buf
,
int
count
)
{
int
err
;
dbg_msg
(
"write %d of %lld bytes, %lld already passed"
,
count
,
vol
->
upd_bytes
,
vol
->
upd_received
);
if
(
ubi
->
ro_mode
)
return
-
EROFS
;
if
(
vol
->
upd_received
+
count
>
vol
->
upd_bytes
)
count
=
vol
->
upd_bytes
-
vol
->
upd_received
;
err
=
copy_from_user
(
vol
->
upd_buf
+
vol
->
upd_received
,
buf
,
count
);
if
(
err
)
return
-
EFAULT
;
vol
->
upd_received
+=
count
;
if
(
vol
->
upd_received
==
vol
->
upd_bytes
)
{
int
len
=
ALIGN
((
int
)
vol
->
upd_bytes
,
ubi
->
min_io_size
);
memset
(
vol
->
upd_buf
+
vol
->
upd_bytes
,
0xFF
,
len
-
vol
->
upd_bytes
);
len
=
ubi_calc_data_len
(
ubi
,
vol
->
upd_buf
,
len
);
err
=
ubi_eba_atomic_leb_change
(
ubi
,
vol
,
vol
->
ch_lnum
,
vol
->
upd_buf
,
len
,
UBI_UNKNOWN
);
if
(
err
)
return
err
;
}
ubi_assert
(
vol
->
upd_received
<=
vol
->
upd_bytes
);
if
(
vol
->
upd_received
==
vol
->
upd_bytes
)
{
vol
->
changing_leb
=
0
;
err
=
count
;
vfree
(
vol
->
upd_buf
);
}
return
err
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment