58 Commits
v0.2 ... master

Author SHA1 Message Date
Maximilian Luz
14cb1ee69f rmtfs: Fix command line argument parsing for '-o' optarg
Commit 2ee01bf ("storage: Try opening the slot-suffixed partition")
introduced a bug where option '-o' is incorrectly specified as having no
argument. Therefore, passing -o with a path incorrectly sets that path
to the default '/boot' one as optarg evaluates to NULL. Fix this by
telling getopt that we expect an argument.

Fixes: 2ee01bf ("storage: Try opening the slot-suffixed partition")
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
2026-01-23 20:11:07 -06:00
Dmitry Baryshkov
f9847a777c Merge pull request #27 from quic-kdybcio/topic/slotsuffix
storage: Try opening the slot-suffixed partition
2025-12-23 04:55:11 +02:00
Konrad Dybcio
f7566e4c82 Merge pull request #28 from z3ntu/modem_study
storage: Add modem_study into partition_table
2025-09-26 13:41:45 +02:00
Luca Weiss
27b3a6f00f storage: Add modem_study into partition_table
The partition /boot/modem_study needs to be served on the Milos/SM7635
Fairphone (Gen. 6) smartphone.

Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
2025-07-28 16:35:04 +02:00
Konrad Dybcio
2ee01bf752 storage: Try opening the slot-suffixed partition
Some devices ship 2 copies of remote partitions (see e.g. #22), which
the current code can't cope with.

Add parsing of a slot suffix (via '-S', single character) and if
passed, retry opening partition (via a partlabel) with it.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
2025-07-02 12:58:29 +02:00
Konrad Dybcio
586372e575 Merge pull request #26 from quic-kdybcio/topic/formatspecifier
sharedmem: Fix build warning on 32-bit arm
2025-06-30 17:39:29 +02:00
Konrad Dybcio
19d1acb728 sharedmem: Fix build warning on 32-bit arm
Format specifiers won't stop biting.

Closes: https://github.com/linux-msm/rmtfs/issues/25
Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
2025-06-30 17:35:31 +02:00
Konrad Dybcio
44facf5694 Merge pull request #24 from loicpoulain/rb1
rmtfs.service: Fix start/stop ordering between rmtfs and NetworkManager
2025-06-30 16:25:23 +02:00
Loic Poulain
5b214f61b9 rmtfs.service: Fix start/stop ordering between rmtfs and NetworkManager
Since rmtfs typically provides resources for wireless and modem-related
processors, it's important to ensure that this service starts before
and stops after NetworkManager.

On platforms like QCOM RB1, this sequencing prevents the Wi-Fi interface(s)
from being left in a dangling state while NetworkManager attempts to tear
down the interface(s):
https://github.com/qualcomm-linux/qcom-deb-images/issues/40#issuecomment-2944265370

The 'Before' dependency directive is ignored if NetworkManager is disabled or absent.

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
2025-06-10 15:10:15 +02:00
Dmitry Baryshkov
b61c22b1cd Merge pull request #23 from lumag/rmtfs-dir-no-qrtr-ns
rmtfs-dir.service.in: Remove dependency on qrtr-ns.service
2025-05-02 03:58:59 +03:00
Luca Weiss
b46235296f rmtfs-dir.service.in: Remove dependency on qrtr-ns.service
The QRTR nameserver has been built into the kernel for years now, drop
the dependency since qrtr-ns.service won't do anything anyways.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
2025-04-24 22:10:21 +03:00
Dmitry Baryshkov
f24570816b Merge pull request #19 from martinezjavier/add-rmtfs-dir-service
Add systemd service to load EFS data from a directory
2025-02-13 21:43:44 +02:00
Konrad Dybcio
33e1e40615 Merge pull request #18 from ipearworks/fix
sharedmem: Fix incorrect usages of `strerror`
2024-03-18 17:09:52 +01:00
Konrad Dybcio
a2df4bd096 Merge pull request #20 from z3ntu/qrtr-ns
rmtfs.service.in: Remove dependency on qrtr-ns.service
2024-03-18 17:09:02 +01:00
Konrad Dybcio
e4e6212c86 Tag stable release
This is the last commit before repository transfer.

It may be useful for some distros which have been shipping this package
for some time already
2024-03-18 17:07:59 +01:00
Luca Weiss
44fcb2ec64 rmtfs.service.in: Remove dependency on qrtr-ns.service
The QRTR nameserver has been built into the kernel for years now, drop
the dependency since qrtr-ns.service won't do anything anyways.
2024-03-11 11:02:29 +01:00
Javier Martinez Canillas
0caf528637 rmtfs-dir.service: Add systemd service to load EFS data from a directory
The EFS data can either be in a partition or a filesystem path. The rmtfs
allows both, but there is only a systemd service to use the former.

Add another systemd service that does the latter. By default, the EFS path
is /var/lib/rmtfs (which is the directory used by msm-cros-efs-loader.sh
and other tools that extract the EFS data) but this can be changed during
build by setting the RMTFS_EFS_PATH environment variable.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
2024-02-07 15:03:20 +01:00
Javier Martinez Canillas
cc5d4df973 rmtfs: Fix a couple of possible uninitialized variables usage
GCC version 13.2.1 20231205 complains about the following:

  cc -Wall -g -O2   -c -o storage.o storage.c
  In function ‘rmtfs_iovec’,
      inlined from ‘handle_rmtfs’ at rmtfs.c:403:4:
  rmtfs.c:224:12: warning: ‘is_write’ may be used uninitialized [-Wmaybe-uninitialized]
    224 |         if (is_write)
        |            ^
  rmtfs.c: In function ‘handle_rmtfs’:
  rmtfs.c:158:17: note: ‘is_write’ was declared here
    158 |         uint8_t is_write;
        |                 ^
  In function ‘rmtfs_iovec’,
      inlined from ‘handle_rmtfs’ at rmtfs.c:403:4:
  rmtfs.c:225:17: warning: ‘rmtfd’ may be used uninitialized [-Wmaybe-uninitialized]
    225 |                 storage_sync(rmtfd);
        |                 ^~~~~~~~~~~~~~~~~~~
  rmtfs.c: In function ‘handle_rmtfs’:
  rmtfs.c:154:23: note: ‘rmtfd’ was declared here
    154 |         struct rmtfd *rmtfd;
        |                       ^~~~~

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
2024-02-07 15:03:20 +01:00
Tianyi Liu
75cb81d197 sharedmem: Fix incorrect usages of strerror
`strerror` takes the `errno` directly as its argument,
negating it will result in an "Unknown error".

Signed-off-by: Tianyi Liu <i.pear@outlook.com>
2024-02-06 15:03:46 +08:00
bbeaavr
7a5ae7e0a5 Add "modem_tng" alias for tunning partition 2023-01-17 23:01:35 -06:00
Luca Weiss
695d0668ff storage: fix out of bounds read
Given that shadow_len is size_t (unsigned integer), subtracting a number
from it will make it wrap around < 0 and become positive again so the
subsequent "if (n > 0)" check will be mostly useless. On AOSP this makes
rmtfs segfault, on Linux distributions rmtfs happily reads beyond the
end of the buf.

Fix this by casting both parameters to ssize_t (which is signed) to
correctly use the if and not read beyond the end of shadow_buf.

Relevant trace using extra debug statements:
  storage_populate_shadow_buf: file=/dev/disk/by-partlabel/fsg shadow_buf=0xffffa5217060 shadow_len=0x280000
  <snip>
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x27fc00 n=0x200
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x27fe00 n=0x200
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x280000 n=0x0 - don't read!
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x280200 n=0x200
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x280400 n=0x200
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x280600 n=0x200
  storage_pread: memcpy shadow_buf=0xffffa5217060 offset=0x280800 n=0x200
  <snip>

Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
2022-07-18 15:27:49 -05:00
Evan Green
b08ef6f98e Use fdatasync instead of O_SYNC on storage
Opening the backing files with O_SYNC makes things really slow. So slow
in fact that the modem times out after 10 seconds waiting for the last
EFS sync to go through. I think this takes forever because rmtfs is
doing 512-byte reads and writes.

One option would be to make this bigger. But a better option is to not
use O_SYNC, but explicitly do an fdatasync() after the iovec operation
is complete. This is better because 1) it's way faster, we no longer see
10-12 second delays at rebooto time, and 2) partial syncs of the EFS
file aren't useful anyway.

Use fdatasync() as opposed to fsync() since it's not important for the
metadata to be synced, just the file contents.

Signed-off-by: Evan Green <evangreen86@gmail.com>
2021-08-09 14:33:25 -07:00
Bjorn Andersson
293ab8babb storage: Sync changes
Open the storage devices as O_SYNC, to make sure modem writes aren't
lingering in the event of power loss or sudden reboot.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2021-04-08 11:56:53 -05:00
Bjorn Andersson
1cc12d3dc1 storage: Use storage_close() to free up resources on exit
Use storage_close() to free up the shadow buffers as well, to avoid any
lingering allocations.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-12-07 08:43:18 -08:00
Bjorn Andersson
bf5cb9faf2 rproc: Make start & stop threads detached
We're not joining the start and stop threads, so create them in detached
state to avoid having their resources lingering.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-12-07 08:42:05 -08:00
Bjorn Andersson
30f5dfb890 rproc: NUL-terminate the modalias
According to valgrind the modalias read from the remoteproc device is
not NUL-terminated, so do this to avoid reading in the weeds.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-12-07 08:17:04 -08:00
Bjorn Andersson
8a1d24a704 rproc: Make state update errors more helpful
Include the reason for the failure to update the "state" sysfs
attribtue in the error message.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-12-07 08:16:18 -08:00
Bjorn Andersson
3449744146 rproc: Support -s for PAS based remoteproc as well
The old mechanism searched for remoteproc instances from the
qcom_q6v5_mss driver, but in modern platforms the MSA based remoteproc
model has been replaced by the PAS based one. As such we use the common
qcom_q6v5_pas driver - as with other subsystems.

Use the modalias to find remoteproc drivers with the mpss-pas or mss-pil
compatible to find these, and fall back to the old heuristics if this
fails.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-11-21 00:02:39 -06:00
Bjorn Andersson
710e6cf908 rmtfs: Exit even though there's no rprocfd
Attempting to shut down a system with rmtfs running without an
associated remoteproc results in systemd waiting forever for the
remoteproc code to never signal that it's done.

Instead exit immediately when signalled, when there's no associated
remoteproc.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-11-20 23:21:05 -06:00
Vincent Knecht
417f04a9a7 storage: Add modem_tunning partition needed for Alcatel Idol 3 devices 2020-11-13 09:02:56 -08:00
John Stultz
0d00985e5e sharedmem: Fix pointer arithmetic warnings.
Building rmtfs on AOSP, we see a lot of the following:
  warning: arithmetic on a pointer to void is a GNU extension

Fix this by casting the void* ptrs to char* when doing pointer
arithmatic.

Signed-off-by: John Stultz <john.stultz@linaro.org>
[AmitP: Fixed cherry-pick conflicts and updated commit log]
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-09-28 10:08:11 -05:00
Amit Pundir
5b1471efa8 storage: Use -o option to override partition by-name
Instead of hardcoding BY_PARTLABEL_PATH for AOSP,
reuse -o option as suggested by Bjorn to expand John's
patch to find correct partition by-name on newer
kernels (which is /dev/block/platform/soc*/*.*/by-name).

For example: On db845c running v5.4+ kernel we run:
rmtfs -o /dev/block/platform/soc@0/1d84000.ufshc/by-name -P -r -s

Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-09-28 10:07:23 -05:00
Amit Pundir
ad5f456c18 sharedmem: Keep /dev/qcom_rmtfs_memX fd open
/dev/qcom_rmtfs_mem0 fd is required to share the data.

Fixes: 9ef260ba6f ("ANDROID: Add Android support")
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-09-28 10:07:20 -05:00
Amit Pundir
9ef260ba6f ANDROID: Add Android support
* Add Android.bp makefile to build rmtfs for AOSP.
* libudev is not supported on AOSP so read
  /sys/class/rmtfs sysfs entries directly.

Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2020-02-03 09:13:59 -08:00
Aníbal Limón
dfb8f3ed1c rmtfs.service.in: Add RestartSec to 1 sec intervals
Systemd has a default restart policy of 5 retries so wait
1 second in each retry because if is too fast will fail to
start properly.

Signed-off-by: Aníbal Limón <anibal.limon@linaro.org>
2020-01-30 22:09:44 -08:00
Aníbal Limón
29eb4a5b06 rmtfs.c: Exit when fail to get rprocfd
When -s option is specified rmtfs handled the start of rproc
but at init may be the /sys entries are not fully populated yet
due to module load/setup so exit with 1 and let systemd restart
the service.

Signed-off-by: Aníbal Limón <anibal.limon@linaro.org>
2020-01-30 11:16:22 -08:00
Bjorn Andersson
df6c19d033 storage: Track opened files without backing storage
Upon populating the shadow_buf the no fd is associated with the rmtfd.
Therefor the next open request will conclude that the rmtfd is available
and use the same entry. Fix this by checking for both associated fd and
shadow_buf in the open call.

Fixes: c35633ab23 ("storage: Allow read only backing storage")
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-28 13:11:53 -07:00
Bjorn Andersson
6d2cfcddfc rmtfs.service: Add systemd service
Add rmtfs.service and install this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-25 11:18:58 -07:00
Sibi Sankar
976aa0ddbe rmtfs: Sync rmtfs server with rproc instance
Add sigterm/sigint handlers to enable graceful rmtfs server
bringdown on first instance of SIGINT/SIGTERM. Start/Stop the
remoteproc instance on RMTFS service up and SIGINT/SIGTERM
respectively. Force quit on second instance of SIGINT/SIGTERM.

Signed-off-by: Sibi Sankar <sibis@codeaurora.org>
[bjorn: Pipe for event loop signaling, reworked /sys traversal]
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-19 00:24:35 -07:00
Bjorn Andersson
42edb9c07a storage: Support operating on raw partitions
Most devices has partitions named modemst1, modemst2, fsg and fsc
backing the rmtfs. Add a new argument '-P' to get the storage
implementation to use these partitions directly instead of files.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-17 12:23:19 -07:00
Bjorn Andersson
c35633ab23 storage: Allow read only backing storage
Add a new argument '-r' to prevent writes back to the backing storage.
This is useful for experimenting with the remote storage, without having
the files overwritten.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-17 12:23:02 -07:00
Bjorn Andersson
e6d703b3c8 storage: Revise API
Pass "struct rmtfd" instead of file descriptors in the interface. This
cleans up the api a little bit, but more importantly allow us to
associate additional things with the remote file descriptors.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-17 12:22:26 -07:00
Bjorn Andersson
152b96981e storage: Rename caller to "remote fd"
The caller (and caller_id) are really "remote file descriptors", so
rename them based on this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-17 12:22:26 -07:00
Bjorn Andersson
886608484b rmtfs: Use pread/pwrite for storage
Instead of relying on an initial lseek, use pread/pwrite. This creates a
cleaner interface towards the storage.c implementation, allowing us to
provide a memory-only implementation of the backing storage.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-07-17 12:22:26 -07:00
Evan Green
cfb76ff6ee storage: Allow specifying the storage directory
Enable the specification of storage paths other than /boot, using
a new -o command line argument. Getoptify the command line arguments
for better processing.
2018-12-19 09:21:06 -08:00
Evan Green
08d20f1646 rmtfs: Better support for EFS backed by files
Currently, in order to back the EFS storage with a regular file,
those files have to be pre-allocated, and with their correct size.
This is especially problematic when preparing a minimal FSG, since
we do not know ahead of time what size to pre-allocate.

Allow reads that go beyond the end of the backing storage to simply
read zeroes. When a write comes in, the file will be automatically
expanded to the correct size. (And should really only be written
if a full sector was pulled out of the modem). For solutions
that use partitions instead of files, this change should be a no-op.
2018-12-19 09:21:06 -08:00
Ben Chan
0d3c49ec5a rmtfs: remove unused cpu_to_le32 and le32_to_cpu functions
This patch addresses the following compiler warnings on unused function:

  rmtfs.c:24:22: warning: unused function 'cpu_to_le32' [-Wunused-function]
  static inline __le32 cpu_to_le32(uint32_t x) { return htole32(x); }
                       ^
  rmtfs.c:25:24: warning: unused function 'le32_to_cpu' [-Wunused-function]
  static inline uint32_t le32_to_cpu(__le32 x) { return le32toh(x); }
                       ^
2018-07-26 06:34:05 -07:00
Ben Chan
b3ea7fdf7b rmtfs: fix the type of the phys_address argument of rmtfs_mem_ptr()
The 'phys_address' argument of rmtfs_mem_read() and rmtfs_mem_write() is
an 'unsigned long' type value, which is then passed to the
'phys_address' argument of rmtfs_mem_ptr(), which is an 'unsigned int'
type value. This patch fixes the mismatch.

Signed-off-by: Ben Chan <benchan@chromium.org>
2018-07-05 07:10:30 -07:00
Brian Norris
577aedad06 sharedmem: use 'unsigned long long' for memory region parsing
I see warnings like this:

sharedmem.c:89:44: warning: incompatible pointer types passing 'uint64_t *' (aka 'unsigned long long *') to parameter of type 'unsigned long *' [-Wincompatible-pointer-types]

Since 'unsigned long' might actually be smaller than 'uint64_t', we
should really upgrade to 'unsigned long long' parsing.

At the same time, the existing error handling was wrong: it should have
been looking for ULONG_MAX (per the man page). Convert that to
ULLONG_MAX to fix that bug while we're at it.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
2018-07-05 07:01:36 -07:00
Brian Norris
5eb67a1fb5 Makefile: allow $(CFLAGS), $(LDFLAGS) override
The caller might have specified CFLAGS or LDFLAGS. Let's respect those.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
2018-07-05 07:01:36 -07:00
Joey Hewitt
a75ad5dc2a sharedmem: support uio device
Also a fix to error-reporting for opening the storage.
2018-05-21 17:05:29 -07:00
Bjorn Andersson
0f800fa433 rmtfs: Don't include ../qrtr
While convenient it's easy to mess things up with the qrtr project in
the include and library path. Drop these and rely on the installed
version of the include and library files.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-01 05:04:50 +00:00
Bjorn Andersson
96a272bccb qmic: Use kernel-style qmic output
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-01-31 20:56:57 -08:00
Bjorn Andersson
cff3f619d5 qmi_rmtfs: Update definition file to match the generated files
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-01 04:39:46 +00:00
Bjorn Andersson
42ed7b4e4c rmtfs: Rework message pump
The message pump is cleaned up from cruft that was added to deal with
multiple services (rmtfs and rfsa) as well as ENETRESET handling.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-01 02:28:17 +00:00
Bjorn Andersson
db86a3b1a5 rmtfs: Migrate to new QMI encoder/decoder library
Utilize the QMI encoder/decoder functions being part of libqrtr instead
of rolling our own.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-01 02:09:35 +00:00
Bjorn Andersson
343817e402 rmtfs: Drop the rfsa service
The rfsa service is not used on any supported targets and should most
likely be implemented in the kernel driver directly, so remove any
traces of it from rmtfs.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2017-09-06 23:15:48 -07:00
Bjorn Andersson
91f765efa8 rmtfs: Update dev node of rmtfs_mem
The kernel driver exposing the shared memory was renamed, update the
path in rmtfs as well.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2017-09-06 23:15:48 -07:00
13 changed files with 1390 additions and 1198 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
rmtfs
*.o
rmtfs.service

13
Android.bp Normal file
View File

@@ -0,0 +1,13 @@
cc_binary {
name: "rmtfs",
vendor: true,
srcs: [
"qmi_rmtfs.c",
"rmtfs.c",
"rproc.c",
"sharedmem.c",
"storage.c",
"util.c",
],
shared_libs: ["libqrtr"],
}

View File

@@ -1,21 +1,31 @@
OUT := rmtfs
CFLAGS := -Wall -g -I../qrtr/lib -O2
LDFLAGS := -L../qrtr -lqrtr -ludev
prefix := /usr/local
CFLAGS += -Wall -g -O2
LDFLAGS += -lqrtr -ludev -lpthread
prefix = /usr/local
bindir := $(prefix)/bin
servicedir := $(prefix)/lib/systemd/system
SRCS := qmi_rmtfs.c qmi_tlv.c rmtfs.c sharedmem.c storage.c util.c
RMTFS_EFS_PATH ?= /var/lib/rmtfs
SRCS := qmi_rmtfs.c rmtfs.c rproc.c sharedmem.c storage.c util.c
OBJS := $(SRCS:.c=.o)
$(OUT): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
%.c: %.qmi
qmic < $<
qmic -k < $<
install: $(OUT)
install -D -m 755 $< $(DESTDIR)$(prefix)/bin/$<
%.service: %.service.in
@sed -e 's+RMTFS_PATH+$(bindir)+g' -e 's+RMTFS_EFS_PATH+$(RMTFS_EFS_PATH)+g' $< > $@
install: $(OUT) rmtfs.service rmtfs-dir.service
@install -D -m 755 $(OUT) $(DESTDIR)$(prefix)/bin/$(OUT)
@install -D -m 644 rmtfs.service $(DESTDIR)$(servicedir)/rmtfs.service
@install -D -m 644 rmtfs-dir.service $(DESTDIR)$(servicedir)/rmtfs-dir.service
clean:
rm -f $(OUT) $(OBJS)
rm -f $(OUT) $(OBJS) rmtfs.service
rm -f $(OUT) $(OBJS) rmtfs-dir.service

View File

@@ -2,599 +2,255 @@
#include <string.h>
#include "qmi_rmtfs.h"
struct rmtfs_open_req *rmtfs_open_req_alloc(unsigned txn)
{
return (struct rmtfs_open_req*)qmi_tlv_init(txn, 1, 0);
}
struct rmtfs_open_req *rmtfs_open_req_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_open_req*)qmi_tlv_decode(buf, len, txn, 0);
}
void *rmtfs_open_req_encode(struct rmtfs_open_req *open_req, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)open_req, len);
}
void rmtfs_open_req_free(struct rmtfs_open_req *open_req)
{
qmi_tlv_free((struct qmi_tlv*)open_req);
}
int rmtfs_open_req_set_path(struct rmtfs_open_req *open_req, char *buf, size_t len)
{
return qmi_tlv_set((struct qmi_tlv*)open_req, 1, buf, len);
}
int rmtfs_open_req_get_path(struct rmtfs_open_req *open_req, char *buf, size_t buflen)
{
size_t len;
char *ptr;
ptr = qmi_tlv_get((struct qmi_tlv*)open_req, 1, &len);
if (!ptr)
return -ENOENT;
if (len >= buflen)
return -ENOMEM;
memcpy(buf, ptr, len);
buf[len] = '\0';
return len;
}
struct rmtfs_open_resp *rmtfs_open_resp_alloc(unsigned txn)
{
return (struct rmtfs_open_resp*)qmi_tlv_init(txn, 1, 2);
}
struct rmtfs_open_resp *rmtfs_open_resp_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_open_resp*)qmi_tlv_decode(buf, len, txn, 2);
}
void *rmtfs_open_resp_encode(struct rmtfs_open_resp *open_resp, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)open_resp, len);
}
void rmtfs_open_resp_free(struct rmtfs_open_resp *open_resp)
{
qmi_tlv_free((struct qmi_tlv*)open_resp);
}
int rmtfs_open_resp_set_result(struct rmtfs_open_resp *open_resp, struct rmtfs_qmi_result *val)
{
return qmi_tlv_set((struct qmi_tlv*)open_resp, 2, val, sizeof(struct rmtfs_qmi_result));
}
struct rmtfs_qmi_result *rmtfs_open_resp_get_result(struct rmtfs_open_resp *open_resp)
{
size_t len;
void *ptr;
ptr = qmi_tlv_get((struct qmi_tlv*)open_resp, 2, &len);
if (!ptr)
return NULL;
if (len != sizeof(struct rmtfs_qmi_result))
return NULL;
return ptr;
}
int rmtfs_open_resp_set_caller_id(struct rmtfs_open_resp *open_resp, uint32_t val)
{
return qmi_tlv_set((struct qmi_tlv*)open_resp, 16, &val, sizeof(uint32_t));
}
int rmtfs_open_resp_get_caller_id(struct rmtfs_open_resp *open_resp, uint32_t *val)
{
uint32_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)open_resp, 16, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint32_t))
return -EINVAL;
*val = *(uint32_t*)ptr;
return 0;
}
struct rmtfs_close_req *rmtfs_close_req_alloc(unsigned txn)
{
return (struct rmtfs_close_req*)qmi_tlv_init(txn, 2, 0);
}
struct rmtfs_close_req *rmtfs_close_req_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_close_req*)qmi_tlv_decode(buf, len, txn, 0);
}
void *rmtfs_close_req_encode(struct rmtfs_close_req *close_req, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)close_req, len);
}
void rmtfs_close_req_free(struct rmtfs_close_req *close_req)
{
qmi_tlv_free((struct qmi_tlv*)close_req);
}
int rmtfs_close_req_set_caller_id(struct rmtfs_close_req *close_req, uint32_t val)
{
return qmi_tlv_set((struct qmi_tlv*)close_req, 1, &val, sizeof(uint32_t));
}
int rmtfs_close_req_get_caller_id(struct rmtfs_close_req *close_req, uint32_t *val)
{
uint32_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)close_req, 1, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint32_t))
return -EINVAL;
*val = *(uint32_t*)ptr;
return 0;
}
struct rmtfs_close_resp *rmtfs_close_resp_alloc(unsigned txn)
{
return (struct rmtfs_close_resp*)qmi_tlv_init(txn, 2, 2);
}
struct rmtfs_close_resp *rmtfs_close_resp_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_close_resp*)qmi_tlv_decode(buf, len, txn, 2);
}
void *rmtfs_close_resp_encode(struct rmtfs_close_resp *close_resp, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)close_resp, len);
}
void rmtfs_close_resp_free(struct rmtfs_close_resp *close_resp)
{
qmi_tlv_free((struct qmi_tlv*)close_resp);
}
int rmtfs_close_resp_set_result(struct rmtfs_close_resp *close_resp, struct rmtfs_qmi_result *val)
{
return qmi_tlv_set((struct qmi_tlv*)close_resp, 2, val, sizeof(struct rmtfs_qmi_result));
}
struct rmtfs_qmi_result *rmtfs_close_resp_get_result(struct rmtfs_close_resp *close_resp)
{
size_t len;
void *ptr;
ptr = qmi_tlv_get((struct qmi_tlv*)close_resp, 2, &len);
if (!ptr)
return NULL;
if (len != sizeof(struct rmtfs_qmi_result))
return NULL;
return ptr;
}
struct rmtfs_iovec_req *rmtfs_iovec_req_alloc(unsigned txn)
{
return (struct rmtfs_iovec_req*)qmi_tlv_init(txn, 3, 0);
}
struct rmtfs_iovec_req *rmtfs_iovec_req_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_iovec_req*)qmi_tlv_decode(buf, len, txn, 0);
}
void *rmtfs_iovec_req_encode(struct rmtfs_iovec_req *iovec_req, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)iovec_req, len);
}
void rmtfs_iovec_req_free(struct rmtfs_iovec_req *iovec_req)
{
qmi_tlv_free((struct qmi_tlv*)iovec_req);
}
int rmtfs_iovec_req_set_caller_id(struct rmtfs_iovec_req *iovec_req, uint32_t val)
{
return qmi_tlv_set((struct qmi_tlv*)iovec_req, 1, &val, sizeof(uint32_t));
}
int rmtfs_iovec_req_get_caller_id(struct rmtfs_iovec_req *iovec_req, uint32_t *val)
{
uint32_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)iovec_req, 1, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint32_t))
return -EINVAL;
*val = *(uint32_t*)ptr;
return 0;
}
int rmtfs_iovec_req_set_direction(struct rmtfs_iovec_req *iovec_req, uint8_t val)
{
return qmi_tlv_set((struct qmi_tlv*)iovec_req, 2, &val, sizeof(uint8_t));
}
int rmtfs_iovec_req_get_direction(struct rmtfs_iovec_req *iovec_req, uint8_t *val)
{
uint8_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)iovec_req, 2, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint8_t))
return -EINVAL;
*val = *(uint8_t*)ptr;
return 0;
}
int rmtfs_iovec_req_set_iovec(struct rmtfs_iovec_req *iovec_req, struct rmtfs_iovec_entry *val, size_t count)
{
return qmi_tlv_set_array((struct qmi_tlv*)iovec_req, 3, 1, val, count, sizeof(struct rmtfs_iovec_entry));
}
struct rmtfs_iovec_entry *rmtfs_iovec_req_get_iovec(struct rmtfs_iovec_req *iovec_req, size_t *count)
{
size_t size;
size_t len;
void *ptr;
ptr = qmi_tlv_get_array((struct qmi_tlv*)iovec_req, 3, 1, &len, &size);
if (!ptr)
return NULL;
if (size != sizeof(struct rmtfs_iovec_entry))
return NULL;
*count = len;
return ptr;
}
int rmtfs_iovec_req_set_is_force_sync(struct rmtfs_iovec_req *iovec_req, uint8_t val)
{
return qmi_tlv_set((struct qmi_tlv*)iovec_req, 4, &val, sizeof(uint8_t));
}
int rmtfs_iovec_req_get_is_force_sync(struct rmtfs_iovec_req *iovec_req, uint8_t *val)
{
uint8_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)iovec_req, 4, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint8_t))
return -EINVAL;
*val = *(uint8_t*)ptr;
return 0;
}
struct rmtfs_iovec_resp *rmtfs_iovec_resp_alloc(unsigned txn)
{
return (struct rmtfs_iovec_resp*)qmi_tlv_init(txn, 3, 2);
}
struct rmtfs_iovec_resp *rmtfs_iovec_resp_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_iovec_resp*)qmi_tlv_decode(buf, len, txn, 2);
}
void *rmtfs_iovec_resp_encode(struct rmtfs_iovec_resp *iovec_resp, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)iovec_resp, len);
}
void rmtfs_iovec_resp_free(struct rmtfs_iovec_resp *iovec_resp)
{
qmi_tlv_free((struct qmi_tlv*)iovec_resp);
}
int rmtfs_iovec_resp_set_result(struct rmtfs_iovec_resp *iovec_resp, struct rmtfs_qmi_result *val)
{
return qmi_tlv_set((struct qmi_tlv*)iovec_resp, 2, val, sizeof(struct rmtfs_qmi_result));
}
struct rmtfs_qmi_result *rmtfs_iovec_resp_get_result(struct rmtfs_iovec_resp *iovec_resp)
{
size_t len;
void *ptr;
ptr = qmi_tlv_get((struct qmi_tlv*)iovec_resp, 2, &len);
if (!ptr)
return NULL;
if (len != sizeof(struct rmtfs_qmi_result))
return NULL;
return ptr;
}
struct rmtfs_alloc_buf_req *rmtfs_alloc_buf_req_alloc(unsigned txn)
{
return (struct rmtfs_alloc_buf_req*)qmi_tlv_init(txn, 4, 0);
}
struct rmtfs_alloc_buf_req *rmtfs_alloc_buf_req_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_alloc_buf_req*)qmi_tlv_decode(buf, len, txn, 0);
}
void *rmtfs_alloc_buf_req_encode(struct rmtfs_alloc_buf_req *alloc_buf_req, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)alloc_buf_req, len);
}
void rmtfs_alloc_buf_req_free(struct rmtfs_alloc_buf_req *alloc_buf_req)
{
qmi_tlv_free((struct qmi_tlv*)alloc_buf_req);
}
int rmtfs_alloc_buf_req_set_caller_id(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t val)
{
return qmi_tlv_set((struct qmi_tlv*)alloc_buf_req, 1, &val, sizeof(uint32_t));
}
int rmtfs_alloc_buf_req_get_caller_id(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t *val)
{
uint32_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)alloc_buf_req, 1, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint32_t))
return -EINVAL;
*val = *(uint32_t*)ptr;
return 0;
}
int rmtfs_alloc_buf_req_set_buff_size(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t val)
{
return qmi_tlv_set((struct qmi_tlv*)alloc_buf_req, 2, &val, sizeof(uint32_t));
}
int rmtfs_alloc_buf_req_get_buff_size(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t *val)
{
uint32_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)alloc_buf_req, 2, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint32_t))
return -EINVAL;
*val = *(uint32_t*)ptr;
return 0;
}
struct rmtfs_alloc_buf_resp *rmtfs_alloc_buf_resp_alloc(unsigned txn)
{
return (struct rmtfs_alloc_buf_resp*)qmi_tlv_init(txn, 4, 2);
}
struct rmtfs_alloc_buf_resp *rmtfs_alloc_buf_resp_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_alloc_buf_resp*)qmi_tlv_decode(buf, len, txn, 2);
}
void *rmtfs_alloc_buf_resp_encode(struct rmtfs_alloc_buf_resp *alloc_buf_resp, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)alloc_buf_resp, len);
}
void rmtfs_alloc_buf_resp_free(struct rmtfs_alloc_buf_resp *alloc_buf_resp)
{
qmi_tlv_free((struct qmi_tlv*)alloc_buf_resp);
}
int rmtfs_alloc_buf_resp_set_result(struct rmtfs_alloc_buf_resp *alloc_buf_resp, struct rmtfs_qmi_result *val)
{
return qmi_tlv_set((struct qmi_tlv*)alloc_buf_resp, 2, val, sizeof(struct rmtfs_qmi_result));
}
struct rmtfs_qmi_result *rmtfs_alloc_buf_resp_get_result(struct rmtfs_alloc_buf_resp *alloc_buf_resp)
{
size_t len;
void *ptr;
ptr = qmi_tlv_get((struct qmi_tlv*)alloc_buf_resp, 2, &len);
if (!ptr)
return NULL;
if (len != sizeof(struct rmtfs_qmi_result))
return NULL;
return ptr;
}
int rmtfs_alloc_buf_resp_set_buff_address(struct rmtfs_alloc_buf_resp *alloc_buf_resp, uint64_t val)
{
return qmi_tlv_set((struct qmi_tlv*)alloc_buf_resp, 16, &val, sizeof(uint64_t));
}
int rmtfs_alloc_buf_resp_get_buff_address(struct rmtfs_alloc_buf_resp *alloc_buf_resp, uint64_t *val)
{
uint64_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)alloc_buf_resp, 16, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint64_t))
return -EINVAL;
*val = *(uint64_t*)ptr;
return 0;
}
struct rmtfs_dev_error_req *rmtfs_dev_error_req_alloc(unsigned txn)
{
return (struct rmtfs_dev_error_req*)qmi_tlv_init(txn, 5, 0);
}
struct rmtfs_dev_error_req *rmtfs_dev_error_req_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_dev_error_req*)qmi_tlv_decode(buf, len, txn, 0);
}
void *rmtfs_dev_error_req_encode(struct rmtfs_dev_error_req *dev_error_req, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)dev_error_req, len);
}
void rmtfs_dev_error_req_free(struct rmtfs_dev_error_req *dev_error_req)
{
qmi_tlv_free((struct qmi_tlv*)dev_error_req);
}
int rmtfs_dev_error_req_set_caller_id(struct rmtfs_dev_error_req *dev_error_req, uint32_t val)
{
return qmi_tlv_set((struct qmi_tlv*)dev_error_req, 1, &val, sizeof(uint32_t));
}
int rmtfs_dev_error_req_get_caller_id(struct rmtfs_dev_error_req *dev_error_req, uint32_t *val)
{
uint32_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)dev_error_req, 1, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint32_t))
return -EINVAL;
*val = *(uint32_t*)ptr;
return 0;
}
struct rmtfs_dev_error_resp *rmtfs_dev_error_resp_alloc(unsigned txn)
{
return (struct rmtfs_dev_error_resp*)qmi_tlv_init(txn, 5, 2);
}
struct rmtfs_dev_error_resp *rmtfs_dev_error_resp_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_dev_error_resp*)qmi_tlv_decode(buf, len, txn, 2);
}
void *rmtfs_dev_error_resp_encode(struct rmtfs_dev_error_resp *dev_error_resp, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)dev_error_resp, len);
}
void rmtfs_dev_error_resp_free(struct rmtfs_dev_error_resp *dev_error_resp)
{
qmi_tlv_free((struct qmi_tlv*)dev_error_resp);
}
int rmtfs_dev_error_resp_set_result(struct rmtfs_dev_error_resp *dev_error_resp, struct rmtfs_qmi_result *val)
{
return qmi_tlv_set((struct qmi_tlv*)dev_error_resp, 2, val, sizeof(struct rmtfs_qmi_result));
}
struct rmtfs_qmi_result *rmtfs_dev_error_resp_get_result(struct rmtfs_dev_error_resp *dev_error_resp)
{
size_t len;
void *ptr;
ptr = qmi_tlv_get((struct qmi_tlv*)dev_error_resp, 2, &len);
if (!ptr)
return NULL;
if (len != sizeof(struct rmtfs_qmi_result))
return NULL;
return ptr;
}
int rmtfs_dev_error_resp_set_status(struct rmtfs_dev_error_resp *dev_error_resp, uint8_t val)
{
return qmi_tlv_set((struct qmi_tlv*)dev_error_resp, 16, &val, sizeof(uint8_t));
}
int rmtfs_dev_error_resp_get_status(struct rmtfs_dev_error_resp *dev_error_resp, uint8_t *val)
{
uint8_t *ptr;
size_t len;
ptr = qmi_tlv_get((struct qmi_tlv*)dev_error_resp, 16, &len);
if (!ptr)
return -ENOENT;
if (len != sizeof(uint8_t))
return -EINVAL;
*val = *(uint8_t*)ptr;
return 0;
}
struct rmtfs_force_sync *rmtfs_force_sync_alloc(unsigned txn)
{
return (struct rmtfs_force_sync*)qmi_tlv_init(txn, 6, 4);
}
struct rmtfs_force_sync *rmtfs_force_sync_parse(void *buf, size_t len, unsigned *txn)
{
return (struct rmtfs_force_sync*)qmi_tlv_decode(buf, len, txn, 4);
}
void *rmtfs_force_sync_encode(struct rmtfs_force_sync *force_sync, size_t *len)
{
return qmi_tlv_encode((struct qmi_tlv*)force_sync, len);
}
void rmtfs_force_sync_free(struct rmtfs_force_sync *force_sync)
{
qmi_tlv_free((struct qmi_tlv*)force_sync);
}
int rmtfs_force_sync_set_caller_id(struct rmtfs_force_sync *force_sync, uint32_t *val, size_t count)
{
return qmi_tlv_set_array((struct qmi_tlv*)force_sync, 1, 1, val, count, sizeof(uint32_t));
}
uint32_t *rmtfs_force_sync_get_caller_id(struct rmtfs_force_sync *force_sync, size_t *count)
{
uint32_t *ptr;
size_t size;
size_t len;
ptr = qmi_tlv_get_array((struct qmi_tlv*)force_sync, 1, 1, &len, &size);
if (!ptr)
return NULL;
if (size != sizeof(uint32_t))
return NULL;
*count = len;
return ptr;
}
struct qmi_elem_info rmtfs_qmi_result_ei[] = {
{
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
.offset = offsetof(struct rmtfs_qmi_result, result),
},
{
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
.offset = offsetof(struct rmtfs_qmi_result, error),
},
{}
};
struct qmi_elem_info rmtfs_iovec_entry_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.offset = offsetof(struct rmtfs_iovec_entry, sector_addr),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.offset = offsetof(struct rmtfs_iovec_entry, phys_offset),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.offset = offsetof(struct rmtfs_iovec_entry, num_sector),
},
{}
};
struct qmi_elem_info rmtfs_open_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = 256,
.elem_size = sizeof(char),
.array_type = VAR_LEN_ARRAY,
.tlv_type = 1,
.offset = offsetof(struct rmtfs_open_req, path)
},
{}
};
struct qmi_elem_info rmtfs_open_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct rmtfs_qmi_result),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_open_resp, result),
.ei_array = rmtfs_qmi_result_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(bool),
.tlv_type = 16,
.offset = offsetof(struct rmtfs_open_resp, caller_id_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.tlv_type = 16,
.offset = offsetof(struct rmtfs_open_resp, caller_id),
},
{}
};
struct qmi_elem_info rmtfs_close_req_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.tlv_type = 1,
.offset = offsetof(struct rmtfs_close_req, caller_id),
},
{}
};
struct qmi_elem_info rmtfs_close_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct rmtfs_qmi_result),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_close_resp, result),
.ei_array = rmtfs_qmi_result_ei,
},
{}
};
struct qmi_elem_info rmtfs_iovec_req_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.tlv_type = 1,
.offset = offsetof(struct rmtfs_iovec_req, caller_id),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_iovec_req, direction),
},
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.tlv_type = 3,
.offset = offsetof(struct rmtfs_iovec_req, iovec_len),
},
{
.data_type = QMI_STRUCT,
.elem_len = 255,
.elem_size = sizeof(struct rmtfs_iovec_entry),
.array_type = VAR_LEN_ARRAY,
.tlv_type = 3,
.offset = offsetof(struct rmtfs_iovec_req, iovec),
.ei_array = rmtfs_iovec_entry_ei,
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.tlv_type = 4,
.offset = offsetof(struct rmtfs_iovec_req, is_force_sync),
},
{}
};
struct qmi_elem_info rmtfs_iovec_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct rmtfs_qmi_result),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_iovec_resp, result),
.ei_array = rmtfs_qmi_result_ei,
},
{}
};
struct qmi_elem_info rmtfs_alloc_buf_req_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.tlv_type = 1,
.offset = offsetof(struct rmtfs_alloc_buf_req, caller_id),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_alloc_buf_req, buff_size),
},
{}
};
struct qmi_elem_info rmtfs_alloc_buf_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct rmtfs_qmi_result),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_alloc_buf_resp, result),
.ei_array = rmtfs_qmi_result_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(bool),
.tlv_type = 16,
.offset = offsetof(struct rmtfs_alloc_buf_resp, buff_address_valid),
},
{
.data_type = QMI_UNSIGNED_8_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint64_t),
.tlv_type = 16,
.offset = offsetof(struct rmtfs_alloc_buf_resp, buff_address),
},
{}
};
struct qmi_elem_info rmtfs_dev_error_req_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.tlv_type = 1,
.offset = offsetof(struct rmtfs_dev_error_req, caller_id),
},
{}
};
struct qmi_elem_info rmtfs_dev_error_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct rmtfs_qmi_result),
.tlv_type = 2,
.offset = offsetof(struct rmtfs_dev_error_resp, result),
.ei_array = rmtfs_qmi_result_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(bool),
.tlv_type = 16,
.offset = offsetof(struct rmtfs_dev_error_resp, status_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.tlv_type = 16,
.offset = offsetof(struct rmtfs_dev_error_resp, status),
},
{}
};
struct qmi_elem_info rmtfs_force_sync_ei[] = {
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.tlv_type = 1,
.offset = offsetof(struct rmtfs_force_sync, caller_id_len),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 10,
.elem_size = sizeof(uint32_t),
.array_type = VAR_LEN_ARRAY,
.tlv_type = 1,
.offset = offsetof(struct rmtfs_force_sync, caller_id),
},
{}
};

View File

@@ -2,19 +2,9 @@
#define __QMI_RMTFS_H__
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
struct qmi_tlv;
struct qmi_tlv *qmi_tlv_init(unsigned txn, unsigned msg_id, unsigned type);
struct qmi_tlv *qmi_tlv_decode(void *buf, size_t len, unsigned *txn, unsigned type);
void *qmi_tlv_encode(struct qmi_tlv *tlv, size_t *len);
void qmi_tlv_free(struct qmi_tlv *tlv);
void *qmi_tlv_get(struct qmi_tlv *tlv, unsigned id, size_t *len);
void *qmi_tlv_get_array(struct qmi_tlv *tlv, unsigned id, unsigned len_size, size_t *len, size_t *size);
int qmi_tlv_set(struct qmi_tlv *tlv, unsigned id, void *buf, size_t len);
int qmi_tlv_set_array(struct qmi_tlv *tlv, unsigned id, unsigned len_size, void *buf, size_t len, size_t size);
#include "libqrtr.h"
#define QMI_RMTFS_RESULT_SUCCESS 0
#define QMI_RMTFS_RESULT_FAILURE 1
@@ -39,158 +29,73 @@ struct rmtfs_iovec_entry {
uint32_t num_sector;
};
struct rmtfs_open_req;
struct rmtfs_open_resp;
struct rmtfs_close_req;
struct rmtfs_close_resp;
struct rmtfs_iovec_req;
struct rmtfs_iovec_resp;
struct rmtfs_alloc_buf_req;
struct rmtfs_alloc_buf_resp;
struct rmtfs_dev_error_req;
struct rmtfs_dev_error_resp;
struct rmtfs_force_sync;
struct rmtfs_open_req {
uint32_t path_len;
char path[256];
};
/*
* rmtfs_open_req message
*/
struct rmtfs_open_req *rmtfs_open_req_alloc(unsigned txn);
struct rmtfs_open_req *rmtfs_open_req_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_open_req_encode(struct rmtfs_open_req *open_req, size_t *len);
void rmtfs_open_req_free(struct rmtfs_open_req *open_req);
struct rmtfs_open_resp {
struct rmtfs_qmi_result result;
bool caller_id_valid;
uint32_t caller_id;
};
int rmtfs_open_req_set_path(struct rmtfs_open_req *open_req, char *buf, size_t len);
int rmtfs_open_req_get_path(struct rmtfs_open_req *open_req, char *buf, size_t buflen);
struct rmtfs_close_req {
uint32_t caller_id;
};
/*
* rmtfs_open_resp message
*/
struct rmtfs_open_resp *rmtfs_open_resp_alloc(unsigned txn);
struct rmtfs_open_resp *rmtfs_open_resp_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_open_resp_encode(struct rmtfs_open_resp *open_resp, size_t *len);
void rmtfs_open_resp_free(struct rmtfs_open_resp *open_resp);
struct rmtfs_close_resp {
struct rmtfs_qmi_result result;
};
int rmtfs_open_resp_set_result(struct rmtfs_open_resp *open_resp, struct rmtfs_qmi_result *val);
struct rmtfs_qmi_result *rmtfs_open_resp_get_result(struct rmtfs_open_resp *open_resp);
struct rmtfs_iovec_req {
uint32_t caller_id;
uint8_t direction;
size_t iovec_len;
struct rmtfs_iovec_entry iovec[255];
uint8_t is_force_sync;
};
int rmtfs_open_resp_set_caller_id(struct rmtfs_open_resp *open_resp, uint32_t val);
int rmtfs_open_resp_get_caller_id(struct rmtfs_open_resp *open_resp, uint32_t *val);
struct rmtfs_iovec_resp {
struct rmtfs_qmi_result result;
};
/*
* rmtfs_close_req message
*/
struct rmtfs_close_req *rmtfs_close_req_alloc(unsigned txn);
struct rmtfs_close_req *rmtfs_close_req_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_close_req_encode(struct rmtfs_close_req *close_req, size_t *len);
void rmtfs_close_req_free(struct rmtfs_close_req *close_req);
struct rmtfs_alloc_buf_req {
uint32_t caller_id;
uint32_t buff_size;
};
int rmtfs_close_req_set_caller_id(struct rmtfs_close_req *close_req, uint32_t val);
int rmtfs_close_req_get_caller_id(struct rmtfs_close_req *close_req, uint32_t *val);
struct rmtfs_alloc_buf_resp {
struct rmtfs_qmi_result result;
bool buff_address_valid;
uint64_t buff_address;
};
/*
* rmtfs_close_resp message
*/
struct rmtfs_close_resp *rmtfs_close_resp_alloc(unsigned txn);
struct rmtfs_close_resp *rmtfs_close_resp_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_close_resp_encode(struct rmtfs_close_resp *close_resp, size_t *len);
void rmtfs_close_resp_free(struct rmtfs_close_resp *close_resp);
struct rmtfs_dev_error_req {
uint32_t caller_id;
};
int rmtfs_close_resp_set_result(struct rmtfs_close_resp *close_resp, struct rmtfs_qmi_result *val);
struct rmtfs_qmi_result *rmtfs_close_resp_get_result(struct rmtfs_close_resp *close_resp);
struct rmtfs_dev_error_resp {
struct rmtfs_qmi_result result;
bool status_valid;
uint8_t status;
};
/*
* rmtfs_iovec_req message
*/
struct rmtfs_iovec_req *rmtfs_iovec_req_alloc(unsigned txn);
struct rmtfs_iovec_req *rmtfs_iovec_req_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_iovec_req_encode(struct rmtfs_iovec_req *iovec_req, size_t *len);
void rmtfs_iovec_req_free(struct rmtfs_iovec_req *iovec_req);
struct rmtfs_force_sync {
size_t caller_id_len;
uint32_t caller_id[10];
};
int rmtfs_iovec_req_set_caller_id(struct rmtfs_iovec_req *iovec_req, uint32_t val);
int rmtfs_iovec_req_get_caller_id(struct rmtfs_iovec_req *iovec_req, uint32_t *val);
int rmtfs_iovec_req_set_direction(struct rmtfs_iovec_req *iovec_req, uint8_t val);
int rmtfs_iovec_req_get_direction(struct rmtfs_iovec_req *iovec_req, uint8_t *val);
int rmtfs_iovec_req_set_iovec(struct rmtfs_iovec_req *iovec_req, struct rmtfs_iovec_entry *val, size_t count);
struct rmtfs_iovec_entry *rmtfs_iovec_req_get_iovec(struct rmtfs_iovec_req *iovec_req, size_t *count);
int rmtfs_iovec_req_set_is_force_sync(struct rmtfs_iovec_req *iovec_req, uint8_t val);
int rmtfs_iovec_req_get_is_force_sync(struct rmtfs_iovec_req *iovec_req, uint8_t *val);
/*
* rmtfs_iovec_resp message
*/
struct rmtfs_iovec_resp *rmtfs_iovec_resp_alloc(unsigned txn);
struct rmtfs_iovec_resp *rmtfs_iovec_resp_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_iovec_resp_encode(struct rmtfs_iovec_resp *iovec_resp, size_t *len);
void rmtfs_iovec_resp_free(struct rmtfs_iovec_resp *iovec_resp);
int rmtfs_iovec_resp_set_result(struct rmtfs_iovec_resp *iovec_resp, struct rmtfs_qmi_result *val);
struct rmtfs_qmi_result *rmtfs_iovec_resp_get_result(struct rmtfs_iovec_resp *iovec_resp);
/*
* rmtfs_alloc_buf_req message
*/
struct rmtfs_alloc_buf_req *rmtfs_alloc_buf_req_alloc(unsigned txn);
struct rmtfs_alloc_buf_req *rmtfs_alloc_buf_req_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_alloc_buf_req_encode(struct rmtfs_alloc_buf_req *alloc_buf_req, size_t *len);
void rmtfs_alloc_buf_req_free(struct rmtfs_alloc_buf_req *alloc_buf_req);
int rmtfs_alloc_buf_req_set_caller_id(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t val);
int rmtfs_alloc_buf_req_get_caller_id(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t *val);
int rmtfs_alloc_buf_req_set_buff_size(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t val);
int rmtfs_alloc_buf_req_get_buff_size(struct rmtfs_alloc_buf_req *alloc_buf_req, uint32_t *val);
/*
* rmtfs_alloc_buf_resp message
*/
struct rmtfs_alloc_buf_resp *rmtfs_alloc_buf_resp_alloc(unsigned txn);
struct rmtfs_alloc_buf_resp *rmtfs_alloc_buf_resp_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_alloc_buf_resp_encode(struct rmtfs_alloc_buf_resp *alloc_buf_resp, size_t *len);
void rmtfs_alloc_buf_resp_free(struct rmtfs_alloc_buf_resp *alloc_buf_resp);
int rmtfs_alloc_buf_resp_set_result(struct rmtfs_alloc_buf_resp *alloc_buf_resp, struct rmtfs_qmi_result *val);
struct rmtfs_qmi_result *rmtfs_alloc_buf_resp_get_result(struct rmtfs_alloc_buf_resp *alloc_buf_resp);
int rmtfs_alloc_buf_resp_set_buff_address(struct rmtfs_alloc_buf_resp *alloc_buf_resp, uint64_t val);
int rmtfs_alloc_buf_resp_get_buff_address(struct rmtfs_alloc_buf_resp *alloc_buf_resp, uint64_t *val);
/*
* rmtfs_dev_error_req message
*/
struct rmtfs_dev_error_req *rmtfs_dev_error_req_alloc(unsigned txn);
struct rmtfs_dev_error_req *rmtfs_dev_error_req_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_dev_error_req_encode(struct rmtfs_dev_error_req *dev_error_req, size_t *len);
void rmtfs_dev_error_req_free(struct rmtfs_dev_error_req *dev_error_req);
int rmtfs_dev_error_req_set_caller_id(struct rmtfs_dev_error_req *dev_error_req, uint32_t val);
int rmtfs_dev_error_req_get_caller_id(struct rmtfs_dev_error_req *dev_error_req, uint32_t *val);
/*
* rmtfs_dev_error_resp message
*/
struct rmtfs_dev_error_resp *rmtfs_dev_error_resp_alloc(unsigned txn);
struct rmtfs_dev_error_resp *rmtfs_dev_error_resp_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_dev_error_resp_encode(struct rmtfs_dev_error_resp *dev_error_resp, size_t *len);
void rmtfs_dev_error_resp_free(struct rmtfs_dev_error_resp *dev_error_resp);
int rmtfs_dev_error_resp_set_result(struct rmtfs_dev_error_resp *dev_error_resp, struct rmtfs_qmi_result *val);
struct rmtfs_qmi_result *rmtfs_dev_error_resp_get_result(struct rmtfs_dev_error_resp *dev_error_resp);
int rmtfs_dev_error_resp_set_status(struct rmtfs_dev_error_resp *dev_error_resp, uint8_t val);
int rmtfs_dev_error_resp_get_status(struct rmtfs_dev_error_resp *dev_error_resp, uint8_t *val);
/*
* rmtfs_force_sync message
*/
struct rmtfs_force_sync *rmtfs_force_sync_alloc(unsigned txn);
struct rmtfs_force_sync *rmtfs_force_sync_parse(void *buf, size_t len, unsigned *txn);
void *rmtfs_force_sync_encode(struct rmtfs_force_sync *force_sync, size_t *len);
void rmtfs_force_sync_free(struct rmtfs_force_sync *force_sync);
int rmtfs_force_sync_set_caller_id(struct rmtfs_force_sync *force_sync, uint32_t *val, size_t count);
uint32_t *rmtfs_force_sync_get_caller_id(struct rmtfs_force_sync *force_sync, size_t *count);
extern struct qmi_elem_info rmtfs_open_req_ei[];
extern struct qmi_elem_info rmtfs_open_resp_ei[];
extern struct qmi_elem_info rmtfs_close_req_ei[];
extern struct qmi_elem_info rmtfs_close_resp_ei[];
extern struct qmi_elem_info rmtfs_iovec_req_ei[];
extern struct qmi_elem_info rmtfs_iovec_resp_ei[];
extern struct qmi_elem_info rmtfs_alloc_buf_req_ei[];
extern struct qmi_elem_info rmtfs_alloc_buf_resp_ei[];
extern struct qmi_elem_info rmtfs_dev_error_req_ei[];
extern struct qmi_elem_info rmtfs_dev_error_resp_ei[];
extern struct qmi_elem_info rmtfs_force_sync_ei[];
#endif

View File

@@ -45,7 +45,7 @@ response close_resp {
request iovec_req {
required u32 caller_id = 1;
required u8 direction = 2;
required iovec_entry iovec[] = 3;
required iovec_entry iovec(255) = 3;
required u8 is_force_sync = 4;
} = 3;
@@ -73,5 +73,5 @@ response dev_error_resp {
} = 5;
indication force_sync {
required u32 caller_id[] = 1;
required u32 caller_id(10) = 1;
} = 6;

11
rmtfs-dir.service.in Normal file
View File

@@ -0,0 +1,11 @@
[Unit]
Description=Qualcomm remotefs service
Before=NetworkManager.service
[Service]
ExecStart=RMTFS_PATH/rmtfs -s -o RMTFS_EFS_PATH
Restart=always
RestartSec=1
[Install]
WantedBy=multi-user.target

697
rmtfs.c
View File

@@ -2,14 +2,18 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libqrtr.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -17,22 +21,13 @@
#include "util.h"
#include "rmtfs.h"
#define RFSA_QMI_SERVICE 28
#define RFSA_QMI_VERSION 1
#define RFSA_QMI_INSTANCE 0
#define RMTFS_QMI_SERVICE 14
#define RMTFS_QMI_VERSION 1
#define RMTFS_QMI_INSTANCE 0
static struct rmtfs_mem *rmem;
/* TODO: include from kernel once it lands */
struct sockaddr_qrtr {
unsigned short sq_family;
uint32_t sq_node;
uint32_t sq_port;
};
static sig_atomic_t sig_int_count;
static char slot_suffix[SLOT_SUFFIX_LEN];
static bool dbgprintf_enabled;
static void dbgprintf(const char *fmt, ...)
@@ -57,191 +52,179 @@ static void qmi_result_error(struct rmtfs_qmi_result *result, unsigned error)
result->error = error;
}
static void rmtfs_open(int sock, unsigned node, unsigned port, void *msg, size_t msg_len)
static void rmtfs_open(int sock, const struct qrtr_packet *pkt)
{
struct rmtfs_qmi_result result = {};
struct rmtfs_open_resp *resp;
struct rmtfs_open_req *req;
struct rmtfs_open_resp resp = {};
struct rmtfs_open_req req = {};
DEFINE_QRTR_PACKET(resp_buf, 256);
struct rmtfd *rmtfd;
unsigned int txn;
ssize_t len;
int caller_id = -1;
unsigned txn;
size_t len;
void *ptr;
char path[256] = {};
int ret;
req = rmtfs_open_req_parse(msg, msg_len, &txn);
if (!req) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_open_req_get_path(req, path, sizeof(path));
ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST,
QMI_RMTFS_OPEN, rmtfs_open_req_ei);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
qmi_result_error(&resp.result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
caller_id = storage_get(node, path);
if (caller_id < 0)
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
rmtfd = storage_open(pkt->node, req.path, slot_suffix);
if (!rmtfd) {
qmi_result_error(&resp.result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
caller_id = storage_get_caller_id(rmtfd);
resp.caller_id = caller_id;
resp.caller_id_valid = true;
respond:
dbgprintf("[RMTFS] open %s => %d (%d:%d)\n", path, caller_id, result.result, result.error);
dbgprintf("[RMTFS] open %s => %d (%d:%d)\n",
req.path, caller_id, resp.result.result, resp.result.error);
resp = rmtfs_open_resp_alloc(txn);
rmtfs_open_resp_set_result(resp, &result);
rmtfs_open_resp_set_caller_id(resp, caller_id);
ptr = rmtfs_open_resp_encode(resp, &len);
if (!ptr)
goto free_resp;
len = qmi_encode_message(&resp_buf,
QMI_RESPONSE, QMI_RMTFS_OPEN, txn, &resp,
rmtfs_open_resp_ei);
if (len < 0) {
fprintf(stderr, "[RMTFS] failed to encode open-response: %s\n",
strerror(-len));
return;
}
ret = qrtr_sendto(sock, node, port, ptr, len);
ret = qrtr_sendto(sock, pkt->node, pkt->port,
resp_buf.data, resp_buf.data_len);
if (ret < 0)
fprintf(stderr, "[RMTFS] failed to send open-response: %s\n", strerror(-ret));
free_resp:
rmtfs_open_resp_free(resp);
rmtfs_open_req_free(req);
fprintf(stderr, "[RMTFS] failed to send open-response: %s\n",
strerror(-ret));
}
static void rmtfs_close(int sock, unsigned node, unsigned port, void *msg, size_t msg_len)
static void rmtfs_close(int sock, const struct qrtr_packet *pkt)
{
struct rmtfs_qmi_result result = {};
struct rmtfs_close_resp *resp;
struct rmtfs_close_req *req;
uint32_t caller_id;
unsigned txn;
size_t len;
void *ptr;
struct rmtfs_close_resp resp = {};
struct rmtfs_close_req req = {};
DEFINE_QRTR_PACKET(resp_buf, 256);
struct rmtfd *rmtfd;
unsigned int txn;
ssize_t len;
int ret;
req = rmtfs_close_req_parse(msg, msg_len, &txn);
if (!req) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_close_req_get_caller_id(req, &caller_id);
ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST,
QMI_RMTFS_CLOSE, rmtfs_close_req_ei);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
qmi_result_error(&resp.result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = storage_put(node, caller_id);
if (ret < 0)
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
rmtfd = storage_get(pkt->node, req.caller_id);
if (!rmtfd) {
qmi_result_error(&resp.result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
storage_close(rmtfd);
rmtfs_mem_free(rmem);
respond:
dbgprintf("[RMTFS] close %d => (%d:%d)\n", caller_id, result.result, result.error);
dbgprintf("[RMTFS] close %s => %d (%d:%d)\n",
req.caller_id, resp.result.result, resp.result.error);
resp = rmtfs_close_resp_alloc(txn);
rmtfs_close_resp_set_result(resp, &result);
ptr = rmtfs_close_resp_encode(resp, &len);
if (!ptr)
goto free_resp;
len = qmi_encode_message(&resp_buf,
QMI_RESPONSE, QMI_RMTFS_CLOSE, txn, &resp,
rmtfs_close_resp_ei);
if (len < 0) {
fprintf(stderr, "[RMTFS] failed to encode close-response: %s\n",
strerror(-len));
return;
}
ret = qrtr_sendto(sock, node, port, ptr, len);
ret = qrtr_sendto(sock, pkt->node, pkt->port,
resp_buf.data, resp_buf.data_len);
if (ret < 0)
fprintf(stderr, "[RMTFS] failed to send close-response: %s\n", strerror(-ret));
free_resp:
rmtfs_close_resp_free(resp);
rmtfs_close_req_free(req);
fprintf(stderr, "[RMTFS] failed to send close-response: %s\n",
strerror(-ret));
}
static void rmtfs_iovec(int sock, unsigned node, unsigned port, void *msg, size_t msg_len)
static void rmtfs_iovec(int sock, struct qrtr_packet *pkt)
{
struct rmtfs_iovec_entry *entries;
struct rmtfs_qmi_result result = {};
struct rmtfs_iovec_resp *resp;
struct rmtfs_iovec_req *req;
unsigned long phys_offset;
uint32_t caller_id;
size_t num_entries;
uint8_t is_write;
uint8_t force;
struct rmtfs_iovec_resp resp = {};
struct rmtfs_iovec_req req = {};
DEFINE_QRTR_PACKET(resp_buf, 256);
struct rmtfd *rmtfd = NULL;
uint32_t caller_id = 0;
size_t num_entries = 0;
off_t sector_base;
uint8_t is_write = 0;
off_t phys_base;
uint8_t force = 0;
unsigned txn;
off_t offset;
ssize_t len;
ssize_t n;
size_t len;
void *ptr;
char buf[SECTOR_SIZE];
int ret;
int fd;
int i;
int j;
req = rmtfs_iovec_req_parse(msg, msg_len, &txn);
if (!req) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_iovec_req_get_caller_id(req, &caller_id);
ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST,
QMI_RMTFS_RW_IOVEC, rmtfs_iovec_req_ei);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
qmi_result_error(&resp.result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_iovec_req_get_direction(req, &is_write);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
caller_id = req.caller_id;
is_write = req.direction;
entries = req.iovec;
num_entries = req.iovec_len;
force = req.is_force_sync;
entries = rmtfs_iovec_req_get_iovec(req, &num_entries);
if (!entries) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_iovec_req_get_is_force_sync(req, &force);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
fd = storage_get_handle(node, caller_id);
if (fd < 0) {
rmtfd = storage_get(pkt->node, caller_id);
if (!rmtfd) {
fprintf(stderr, "[RMTFS] iovec request for non-existing caller\n");
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
qmi_result_error(&resp.result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
for (i = 0; i < num_entries; i++) {
phys_offset = entries[i].phys_offset;
n = lseek(fd, entries[i].sector_addr * SECTOR_SIZE, SEEK_SET);
if (n < 0) {
fprintf(stderr, "[RMTFS] failed to seek sector %d\n", entries[i].sector_addr);
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
phys_base = entries[i].phys_offset;
sector_base = entries[i].sector_addr * SECTOR_SIZE;
offset = 0;
for (j = 0; j < entries[i].num_sector; j++) {
if (is_write) {
n = rmtfs_mem_read(rmem, phys_offset, buf, SECTOR_SIZE);
n = write(fd, buf, n);
n = rmtfs_mem_read(rmem, phys_base + offset, buf, SECTOR_SIZE);
if (n == SECTOR_SIZE)
n = storage_pwrite(rmtfd, buf, n, sector_base + offset);
} else {
n = read(fd, buf, SECTOR_SIZE);
n = rmtfs_mem_write(rmem, phys_offset, buf, n);
n = storage_pread(rmtfd, buf, SECTOR_SIZE, sector_base + offset);
if (n >= 0) {
if (n < SECTOR_SIZE)
memset(buf + n, 0, SECTOR_SIZE - n);
n = rmtfs_mem_write(rmem, phys_base + offset, buf, SECTOR_SIZE);
}
}
if (n != SECTOR_SIZE) {
fprintf(stderr, "[RMTFS] failed to %s sector %d\n",
is_write ? "write" : "read", entries[i].sector_addr + j);
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
qmi_result_error(&resp.result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
phys_offset += SECTOR_SIZE;
offset += SECTOR_SIZE;
}
}
respond:
dbgprintf("[RMTFS] iovec %d, %sforced => (%d:%d)\n", caller_id, force ? "" : "not ",
result.result, result.error);
resp.result.result, resp.result.error);
if (is_write)
storage_sync(rmtfd);
for (i = 0; i < num_entries; i++) {
dbgprintf("[RMTFS] %s %d:%d 0x%x\n", is_write ? "write" : "read",
entries[i].sector_addr,
@@ -249,168 +232,136 @@ respond:
entries[i].phys_offset);
}
resp = rmtfs_iovec_resp_alloc(txn);
rmtfs_iovec_resp_set_result(resp, &result);
ptr = rmtfs_iovec_resp_encode(resp, &len);
if (!ptr)
goto free_resp;
len = qmi_encode_message(&resp_buf,
QMI_RESPONSE, QMI_RMTFS_RW_IOVEC, txn, &resp,
rmtfs_iovec_resp_ei);
if (len < 0) {
fprintf(stderr, "[RMTFS] failed to encode iovec-response: %s\n",
strerror(-len));
return;
}
ret = qrtr_sendto(sock, node, port, ptr, len);
ret = qrtr_sendto(sock, pkt->node, pkt->port,
resp_buf.data, resp_buf.data_len);
if (ret < 0)
fprintf(stderr, "[RMTFS] failed to send iovec-response: %s\n", strerror(-ret));
free_resp:
rmtfs_iovec_resp_free(resp);
rmtfs_iovec_req_free(req);
fprintf(stderr, "[RMTFS] failed to send iovec-response: %s\n",
strerror(-ret));
}
static void rmtfs_alloc_buf(int sock, unsigned node, unsigned port, void *msg, size_t msg_len)
static void rmtfs_alloc_buf(int sock, struct qrtr_packet *pkt)
{
struct rmtfs_alloc_buf_resp *resp;
struct rmtfs_alloc_buf_req *req;
struct rmtfs_qmi_result result = {};
uint32_t alloc_size;
uint32_t caller_id;
int64_t address;
struct rmtfs_alloc_buf_resp resp = {};
struct rmtfs_alloc_buf_req req = {};
DEFINE_QRTR_PACKET(resp_buf, 256);
uint32_t alloc_size = 0;
uint32_t caller_id = 0;
int64_t address = 0;
unsigned txn;
size_t len;
void *ptr;
ssize_t len;
int ret;
req = rmtfs_alloc_buf_req_parse(msg, msg_len, &txn);
if (!req) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST,
QMI_RMTFS_ALLOC_BUFF, rmtfs_alloc_buf_req_ei);
if (ret < 0) {
qmi_result_error(&resp.result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_alloc_buf_req_get_caller_id(req, &caller_id);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_alloc_buf_req_get_buff_size(req, &alloc_size);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
caller_id = req.caller_id;
alloc_size = req.buff_size;
address = rmtfs_mem_alloc(rmem, alloc_size);
if (address < 0)
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
if (address < 0) {
qmi_result_error(&resp.result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
resp.buff_address = address;
resp.buff_address_valid = true;
respond:
dbgprintf("[RMTFS] alloc %d, %d => 0x%lx (%d:%d)\n", caller_id, alloc_size, address, result.result, result.error);
dbgprintf("[RMTFS] alloc %d, %d => 0x%lx (%d:%d)\n", caller_id, alloc_size, address, resp.result.result, resp.result.error);
resp = rmtfs_alloc_buf_resp_alloc(txn);
rmtfs_alloc_buf_resp_set_result(resp, &result);
rmtfs_alloc_buf_resp_set_buff_address(resp, address);
ptr = rmtfs_alloc_buf_resp_encode(resp, &len);
if (!ptr)
goto free_resp;
len = qmi_encode_message(&resp_buf,
QMI_RESPONSE, QMI_RMTFS_ALLOC_BUFF, txn, &resp,
rmtfs_alloc_buf_resp_ei);
if (len < 0) {
fprintf(stderr, "[RMTFS] failed to encode alloc-buf-response: %s\n",
strerror(-len));
return;
}
ret = qrtr_sendto(sock, node, port, ptr, len);
ret = qrtr_sendto(sock, pkt->node, pkt->port,
resp_buf.data, resp_buf.data_len);
if (ret < 0)
fprintf(stderr, "[RMTFS] failed to send alloc-response: %s\n", strerror(-ret));
free_resp:
rmtfs_alloc_buf_resp_free(resp);
rmtfs_alloc_buf_req_free(req);
fprintf(stderr, "[RMTFS] failed to send alloc-buf-response: %s\n",
strerror(-ret));
}
static void rmtfs_get_dev_error(int sock, unsigned node, unsigned port, void *msg, size_t msg_len)
static void rmtfs_get_dev_error(int sock, struct qrtr_packet *pkt)
{
struct rmtfs_dev_error_resp *resp;
struct rmtfs_dev_error_req *req;
struct rmtfs_qmi_result result = {};
uint32_t caller_id;
int dev_error;
struct rmtfs_dev_error_resp resp = {};
struct rmtfs_dev_error_req req = {};
DEFINE_QRTR_PACKET(resp_buf, 256);
struct rmtfd *rmtfd;
unsigned txn;
size_t len;
void *ptr;
ssize_t len;
int ret;
req = rmtfs_dev_error_req_parse(msg, msg_len, &txn);
if (!req) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
ret = rmtfs_dev_error_req_get_caller_id(req, &caller_id);
ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST,
QMI_RMTFS_GET_DEV_ERROR,
rmtfs_dev_error_req_ei);
if (ret < 0) {
qmi_result_error(&result, QMI_RMTFS_ERR_MALFORMED_MSG);
qmi_result_error(&resp.result, QMI_RMTFS_ERR_MALFORMED_MSG);
goto respond;
}
dev_error = storage_get_error(node, caller_id);
if (dev_error < 0)
qmi_result_error(&result, QMI_RMTFS_ERR_INTERNAL);
rmtfd = storage_get(pkt->node, req.caller_id);
if (rmtfd) {
qmi_result_error(&resp.result, QMI_RMTFS_ERR_INTERNAL);
goto respond;
}
resp.status = storage_get_error(rmtfd);
resp.status_valid = true;
respond:
dbgprintf("[RMTFS] dev_error %d => %d (%d:%d)\n", caller_id, dev_error, result.result, result.error);
dbgprintf("[RMTFS] dev_error %d => %d (%d:%d)\n", req.caller_id, resp.status, resp.result.result, resp.result.error);
resp = rmtfs_dev_error_resp_alloc(txn);
rmtfs_dev_error_resp_set_result(resp, &result);
rmtfs_dev_error_resp_set_status(resp, dev_error);
ptr = rmtfs_dev_error_resp_encode(resp, &len);
if (!ptr)
goto free_resp;
ret = qrtr_sendto(sock, node, port, ptr, len);
if (ret < 0)
fprintf(stderr, "[RMTFS] failed to send error-response: %s\n", strerror(-ret));
free_resp:
rmtfs_dev_error_resp_free(resp);
rmtfs_dev_error_req_free(req);
}
static int handle_rfsa(int sock)
{
struct sockaddr_qrtr sq;
socklen_t sl;
char buf[4096];
int ret;
sl = sizeof(sq);
ret = recvfrom(sock, buf, sizeof(buf), 0, (void *)&sq, &sl);
if (ret < 0) {
ret = -errno;
if (ret != -ENETRESET)
fprintf(stderr, "[RFSA] recvfrom failed: %d\n", ret);
return ret;
len = qmi_encode_message(&resp_buf,
QMI_RESPONSE, QMI_RMTFS_GET_DEV_ERROR, txn,
&resp, rmtfs_dev_error_resp_ei);
if (len < 0) {
fprintf(stderr, "[RMTFS] failed to encode dev-error-response: %s\n",
strerror(-len));
return;
}
dbgprintf("[RFSA] packet; from: %d:%d\n", sq.sq_node, sq.sq_port);
if (dbgprintf_enabled)
print_hex_dump("[RFSA <-]", buf, ret);
return 0;
ret = qrtr_sendto(sock, pkt->node, pkt->port,
resp_buf.data, resp_buf.data_len);
if (ret < 0)
fprintf(stderr, "[RMTFS] failed to send dev-error-response: %s\n",
strerror(-ret));
}
static int rmtfs_bye(uint32_t node, void *data)
static int rmtfs_bye(uint32_t node)
{
dbgprintf("[RMTFS] bye from %d\n", node);
return 0;
}
static int rmtfs_del_client(uint32_t node, uint32_t port, void *data)
static int rmtfs_del_client(uint32_t node, uint32_t port)
{
dbgprintf("[RMTFS] del_client %d:%d\n", node, port);
return 0;
}
struct qrtr_ind_ops rmtfs_ctrl_ops = {
.bye = rmtfs_bye,
.del_client = rmtfs_del_client,
};
static int handle_rmtfs(int sock)
{
struct sockaddr_qrtr sq;
struct qmi_packet *qmi;
struct qrtr_packet pkt;
unsigned int msg_id;
socklen_t sl;
char buf[4096];
int ret;
@@ -426,134 +377,212 @@ static int handle_rmtfs(int sock)
dbgprintf("[RMTFS] packet; from: %d:%d\n", sq.sq_node, sq.sq_port);
if (qrtr_is_ctrl_addr(&sq)) {
return qrtr_handle_ctrl_msg(&sq, buf, sizeof(buf),
&rmtfs_ctrl_ops, NULL);
ret = qrtr_decode(&pkt, buf, ret, &sq);
if (ret < 0) {
fprintf(stderr, "[RMTFS] unable to decode qrtr packet\n");
return ret;
}
qmi = (struct qmi_packet*)buf;
if (qmi->msg_len != ret - sizeof(struct qmi_packet)) {
fprintf(stderr, "[RMTFS] Invalid length of incoming qmi request\n");
return -EINVAL;
}
switch (pkt.type) {
case QRTR_TYPE_BYE:
return rmtfs_bye(pkt.node);
case QRTR_TYPE_DEL_CLIENT:
return rmtfs_del_client(pkt.node, pkt.port);
case QRTR_TYPE_DATA:
ret = qmi_decode_header(&pkt, &msg_id);
if (ret < 0)
return ret;
switch (qmi->msg_id) {
case QMI_RMTFS_OPEN:
rmtfs_open(sock, sq.sq_node, sq.sq_port, qmi, qmi->msg_len);
break;
case QMI_RMTFS_CLOSE:
rmtfs_close(sock, sq.sq_node, sq.sq_port, qmi, qmi->msg_len);
break;
case QMI_RMTFS_RW_IOVEC:
rmtfs_iovec(sock, sq.sq_node, sq.sq_port, qmi, qmi->msg_len);
break;
case QMI_RMTFS_ALLOC_BUFF:
rmtfs_alloc_buf(sock, sq.sq_node, sq.sq_port, qmi, qmi->msg_len);
break;
case QMI_RMTFS_GET_DEV_ERROR:
rmtfs_get_dev_error(sock, sq.sq_node, sq.sq_port, qmi, qmi->msg_len);
break;
default:
fprintf(stderr, "[RMTFS] Unknown request: %d\n", qmi->msg_id);
ret = -EINVAL;
break;
switch (msg_id) {
case QMI_RMTFS_OPEN:
rmtfs_open(sock, &pkt);
break;
case QMI_RMTFS_CLOSE:
rmtfs_close(sock, &pkt);
break;
case QMI_RMTFS_RW_IOVEC:
rmtfs_iovec(sock, &pkt);
break;
case QMI_RMTFS_ALLOC_BUFF:
rmtfs_alloc_buf(sock, &pkt);
break;
case QMI_RMTFS_GET_DEV_ERROR:
rmtfs_get_dev_error(sock, &pkt);
break;
default:
fprintf(stderr, "[RMTFS] Unknown request: %d\n", msg_id);
break;
}
return 0;
}
return ret;
}
static int register_services(int rfsa_fd, int rmtfs_fd)
static int sig_int_count;
static int run_rmtfs(int rprocfd)
{
bool sig_int_handled = false;
int rmtfs_fd;
fd_set rfds;
char done;
int nfds;
int ret;
ret = qrtr_publish(rfsa_fd, RFSA_QMI_SERVICE, RFSA_QMI_VERSION, RFSA_QMI_INSTANCE);
rmtfs_fd = qrtr_open(RMTFS_QMI_SERVICE);
if (rmtfs_fd < 0) {
fprintf(stderr, "failed to create qrtr socket\n");
return rmtfs_fd;
}
dbgprintf("registering services\n");
ret = qrtr_publish(rmtfs_fd, RMTFS_QMI_SERVICE,
RMTFS_QMI_VERSION, RMTFS_QMI_INSTANCE);
if (ret < 0) {
fprintf(stderr, "failed to publish rfsa service");
fprintf(stderr, "failed to publish rmtfs service");
return ret;
}
ret = qrtr_publish(rmtfs_fd, RMTFS_QMI_SERVICE, RMTFS_QMI_VERSION, RMTFS_QMI_INSTANCE);
if (ret < 0) {
fprintf(stderr, "failed to publish misc ta service");
if (rprocfd >= 0)
rproc_start();
qrtr_bye(rfsa_fd, RFSA_QMI_SERVICE, RFSA_QMI_VERSION, RFSA_QMI_INSTANCE);
return ret;
for (;;) {
if (sig_int_count == 1 && !sig_int_handled) {
if (rprocfd < 0)
break;
rproc_stop();
sig_int_handled = true;
} else if (sig_int_count > 1) {
break;
}
FD_ZERO(&rfds);
FD_SET(rmtfs_fd, &rfds);
if (rprocfd >= 0)
FD_SET(rprocfd, &rfds);
nfds = MAX(rmtfs_fd, rprocfd) + 1;
ret = select(nfds, &rfds, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR)
break;
else if (ret < 0 && errno == EINTR)
continue;
if (rprocfd >= 0 && FD_ISSET(rprocfd, &rfds)) {
ret = read(rprocfd, &done, 1);
if (!ret || done == 'Y')
break;
}
if (FD_ISSET(rmtfs_fd, &rfds)) {
ret = handle_rmtfs(rmtfs_fd);
if (ret == -ENETRESET)
break;
}
}
return 0;
close(rmtfs_fd);
return ret;
}
static void sig_int_handler(int signo)
{
sig_int_count++;
}
int main(int argc, char **argv)
{
bool do_register = true;
int rmtfs_fd;
int rfsa_fd;
fd_set rfds;
int nfds;
struct sigaction action;
bool use_partitions = false;
bool read_only = false;
int rprocfd = -1;
int ret;
int option;
const char *storage_root = NULL;
if (argc == 2 && strcmp(argv[1], "-v") == 0)
dbgprintf_enabled = true;
while ((option = getopt(argc, argv, "o:S:Prsv")) != -1) {
switch (option) {
/*
* -o sets the directory where EFS images are stored,
* or sets the directory from where raw EFS partitions
* can be picked by-name when used with -P option.
*/
case 'o':
storage_root = optarg;
break;
/* -P to find and use raw EFS partitions */
case 'P':
use_partitions = true;
break;
/* -r to avoid writing to storage */
case 'r':
read_only = true;
break;
/* enable sync for the mss rproc instance */
case 's':
rprocfd = rproc_init();
if (rprocfd < 0) {
fprintf(stderr, "Failed to get rprocfd\n");
return 1;
}
break;
/* Partlabel slot suffix on A/B devices */
case 'S':
if (strnlen(optarg, 1 + 1) != 1) {
fprintf(stderr, "Couldn't parse slot name (too long?)\n");
return -1;
}
ret = snprintf(slot_suffix, SLOT_SUFFIX_LEN, "_%s", optarg);
if (ret != SLOT_SUFFIX_LEN - 1)
return -1;
dbgprintf("Using slot %s\n", slot_suffix);
break;
/* -v is for verbose */
case 'v':
dbgprintf_enabled = 1;
break;
case '?':
fprintf(stderr, "Unknown option: -%c\n", option);
return 1;
}
}
sigemptyset(&action.sa_mask);
action.sa_handler = sig_int_handler;
action.sa_flags = 0;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
rmem = rmtfs_mem_open();
if (!rmem)
return 1;
ret = storage_open();
ret = storage_init(storage_root, read_only, use_partitions);
if (ret) {
fprintf(stderr, "failed to initialize storage system\n");
goto close_rmtfs_mem;
}
rfsa_fd = qrtr_open(RFSA_QMI_SERVICE);
if (rfsa_fd < 0) {
fprintf(stderr, "failed to create qrtr socket\n");
goto close_storage;
}
do {
ret = run_rmtfs(rprocfd);
} while (ret == -ENETRESET);
rmtfs_fd = qrtr_open(RMTFS_QMI_SERVICE);
if (rmtfs_fd < 0) {
fprintf(stderr, "failed to create qrtr socket\n");
goto close_storage;
}
for (;;) {
if (do_register) {
dbgprintf("registering services\n");
ret = register_services(rfsa_fd, rmtfs_fd);
if (ret)
break;
do_register = false;
}
FD_ZERO(&rfds);
FD_SET(rfsa_fd, &rfds);
FD_SET(rmtfs_fd, &rfds);
nfds = MAX(rfsa_fd, rmtfs_fd) + 1;
ret = select(nfds, &rfds, NULL, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "select failed: %d\n", ret);
break;
} else if (ret == 0) {
continue;
}
if (FD_ISSET(rfsa_fd, &rfds))
ret = handle_rfsa(rfsa_fd);
else if (FD_ISSET(rmtfs_fd, &rfds))
ret = handle_rmtfs(rmtfs_fd);
if (ret == -ENETRESET)
do_register = true;
}
qrtr_bye(rmtfs_fd, RMTFS_QMI_SERVICE, RMTFS_QMI_VERSION, RMTFS_QMI_INSTANCE);
unpublish_rfsa:
qrtr_bye(rfsa_fd, RFSA_QMI_SERVICE, RFSA_QMI_VERSION, RFSA_QMI_INSTANCE);
close_storage:
storage_close();
storage_exit();
close_rmtfs_mem:
rmtfs_mem_close(rmem);

23
rmtfs.h
View File

@@ -23,11 +23,22 @@ void rmtfs_mem_free(struct rmtfs_mem *rmem);
ssize_t rmtfs_mem_read(struct rmtfs_mem *rmem, unsigned long phys_address, void *buf, ssize_t len);
ssize_t rmtfs_mem_write(struct rmtfs_mem *rmem, unsigned long phys_address, const void *buf, ssize_t len);
int storage_open(void);
int storage_get(unsigned node, const char *path);
int storage_put(unsigned node, int caller_id);
int storage_get_handle(unsigned node, int caller_id);
int storage_get_error(unsigned node, int caller_id);
void storage_close(void);
struct rmtfd;
int storage_init(const char *storage_root, bool read_only, bool use_partitions);
#define SLOT_SUFFIX_LEN (2 + 1) /* "_a" or "_b", null-terminated */
struct rmtfd *storage_open(unsigned node, const char *path, const char *slot_suffix);
struct rmtfd *storage_get(unsigned node, int caller_id);
void storage_close(struct rmtfd *rmtfd);
int storage_get_caller_id(const struct rmtfd *rmtfd);
int storage_get_error(const struct rmtfd *rmtfd);
void storage_exit(void);
ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset);
ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset);
int storage_sync(struct rmtfd *rmtfd);
int rproc_init(void);
int rproc_start(void);
int rproc_stop(void);
#endif

11
rmtfs.service.in Normal file
View File

@@ -0,0 +1,11 @@
[Unit]
Description=Qualcomm remotefs service
Before=NetworkManager.service
[Service]
ExecStart=RMTFS_PATH/rmtfs -r -P -s
Restart=always
RestartSec=1
[Install]
WantedBy=multi-user.target

225
rproc.c Normal file
View File

@@ -0,0 +1,225 @@
#include <sys/syscall.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include "rmtfs.h"
#define RPROC_BASE_PATH "/sys/bus/platform/drivers/qcom-q6v5-mss/"
#define RPROC_CLASS_PATH "/sys/class/remoteproc/"
static pthread_t start_thread;
static pthread_t stop_thread;
static int rproc_state_fd;
static int rproc_pipe[2];
static int rproc_init_by_modalias(void)
{
struct dirent *rproc_de;
char modalias[256];
DIR *base_dir;
int modalias_fd;
int rproc_fd;
int state_fd = -1;
int base_fd;
int ret;
base_fd = open(RPROC_CLASS_PATH, O_RDONLY | O_DIRECTORY);
if (base_fd < 0)
return -1;
base_dir = fdopendir(base_fd);
if (!base_dir) {
fprintf(stderr, "failed to open remoteproc class path\n");
close(base_fd);
return -1;
}
while (state_fd < 0 && (rproc_de = readdir(base_dir)) != NULL) {
if (!strcmp(rproc_de->d_name, ".") ||
!strcmp(rproc_de->d_name, ".."))
continue;
rproc_fd = openat(base_fd, rproc_de->d_name, O_RDONLY | O_DIRECTORY);
if (rproc_fd < 0)
continue;
modalias_fd = openat(rproc_fd, "device/modalias", O_RDONLY);
if (modalias_fd < 0)
goto close_rproc_fd;
ret = read(modalias_fd, modalias, sizeof(modalias) - 1);
if (ret < 0)
goto close_modalias_fd;
modalias[ret] = '\0';
if (!strstr(modalias, "-mpss-pas") && !strstr(modalias, "-mss-pil"))
goto close_modalias_fd;
state_fd = openat(rproc_fd, "state", O_WRONLY);
if (state_fd < 0) {
fprintf(stderr,
"unable to open remoteproc \"state\" control file of %s\n",
rproc_de->d_name);
}
close_modalias_fd:
close(modalias_fd);
close_rproc_fd:
close(rproc_fd);
}
closedir(base_dir);
close(base_fd);
return state_fd;
}
static int rproc_init_by_mss_driver(void)
{
struct dirent *device_de;
struct dirent *rproc_de;
int rproc_base_fd;
DIR *rproc_dir;
DIR *base_dir;
int device_fd;
int rproc_fd;
int state_fd = -1;
int base_fd;
base_fd = open(RPROC_BASE_PATH, O_RDONLY | O_DIRECTORY);
if (base_fd < 0)
return -1;
base_dir = fdopendir(base_fd);
if (!base_dir) {
fprintf(stderr, "failed to open mss driver path\n");
close(base_fd);
return -1;
}
while (state_fd < 0 && (device_de = readdir(base_dir)) != NULL) {
if (!strcmp(device_de->d_name, ".") ||
!strcmp(device_de->d_name, ".."))
continue;
device_fd = openat(base_fd, device_de->d_name, O_RDONLY | O_DIRECTORY);
if (device_fd < 0)
continue;
rproc_base_fd = openat(device_fd, "remoteproc", O_RDONLY | O_DIRECTORY);
if (rproc_base_fd < 0) {
close(device_fd);
continue;
}
rproc_dir = fdopendir(rproc_base_fd);
while (state_fd < 0 && (rproc_de = readdir(rproc_dir)) != NULL) {
if (!strcmp(rproc_de->d_name, ".") ||
!strcmp(rproc_de->d_name, ".."))
continue;
rproc_fd = openat(rproc_base_fd, rproc_de->d_name, O_RDONLY | O_DIRECTORY);
if (rproc_fd < 0)
continue;
state_fd = openat(rproc_fd, "state", O_WRONLY);
if (state_fd < 0) {
fprintf(stderr,
"unable to open remoteproc \"state\" control file of %s\n",
device_de->d_name);
}
close(rproc_fd);
}
closedir(rproc_dir);
close(rproc_base_fd);
close(device_fd);
}
closedir(base_dir);
close(base_fd);
return state_fd;
}
int rproc_init(void)
{
int state_fd;
int ret;
state_fd = rproc_init_by_modalias();
if (state_fd < 0) {
state_fd = rproc_init_by_mss_driver();
if (state_fd < 0)
return -1;
}
ret = pipe(rproc_pipe);
if (ret < 0) {
close(state_fd);
return -1;
}
rproc_state_fd = state_fd;
return rproc_pipe[0];
}
static void *do_rproc_start(void *unused)
{
ssize_t ret;
ret = pwrite(rproc_state_fd, "start", 5, 0);
if (ret < 4) {
fprintf(stderr, "failed to update start state: %s\n",
strerror(errno));
}
return NULL;
}
int rproc_start()
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
return pthread_create(&start_thread, &attr, do_rproc_start, NULL);
}
static void *do_rproc_stop(void *unused)
{
ssize_t ret;
ret = pwrite(rproc_state_fd, "stop", 4, 0);
if (ret < 4) {
fprintf(stderr, "failed to update stop state: %s\n",
strerror(errno));
}
ret = write(rproc_pipe[1], "Y", 1);
if (ret != 1) {
fprintf(stderr, "failed to signal event loop about exit\n");
exit(0);
}
return NULL;
}
int rproc_stop(void)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
return pthread_create(&stop_thread, &attr, do_rproc_stop, NULL);
}

View File

@@ -4,7 +4,12 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#ifndef ANDROID
#include <libudev.h>
#else
#include <sys/endian.h>
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,10 +27,12 @@ struct rmtfs_mem {
int fd;
};
#ifndef ANDROID
static int parse_hex_sysattr(struct udev_device *dev, const char *name,
unsigned long *value)
uint64_t *value)
{
unsigned long val;
unsigned long long val;
const char *buf;
char *endptr;
@@ -34,8 +41,8 @@ static int parse_hex_sysattr(struct udev_device *dev, const char *name,
return -ENOENT;
errno = 0;
val = strtoul(buf, &endptr, 16);
if ((val == LONG_MAX && errno == ERANGE) || endptr == buf) {
val = strtoull(buf, &endptr, 16);
if ((val == ULLONG_MAX && errno == ERANGE) || endptr == buf) {
return -errno;
}
@@ -54,7 +61,7 @@ static int rmtfs_mem_open_rfsa(struct rmtfs_mem *rmem, int client_id)
int ret;
int fd;
sprintf(path, "/dev/qcom_rfsa%d", client_id);
sprintf(path, "/dev/qcom_rmtfs_mem%d", client_id);
fd = open(path, O_RDWR);
if (fd < 0) {
@@ -114,6 +121,150 @@ err_close_fd:
return -saved_errno;
}
static int rmtfs_mem_open_uio(struct rmtfs_mem *rmem, int client_id)
{
struct udev_device *dev;
struct udev *udev;
int saved_errno;
struct stat sb;
char path[32];
int ret;
int fd;
snprintf(path, sizeof(path), "/dev/qcom_rmtfs_uio%d", client_id);
fd = open(path, O_RDWR);
if (fd < 0) {
saved_errno = errno;
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return -saved_errno;
}
rmem->fd = fd;
ret = fstat(fd, &sb);
if (ret < 0) {
saved_errno = errno;
fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
close(fd);
goto err_close_fd;
}
udev = udev_new();
if (!udev) {
saved_errno = errno;
fprintf(stderr, "failed to create udev context\n");
goto err_close_fd;
}
dev = udev_device_new_from_devnum(udev, 'c', sb.st_rdev);
if (!dev) {
saved_errno = errno;
fprintf(stderr, "unable to find udev device\n");
goto err_unref_udev;
}
ret = parse_hex_sysattr(dev, "maps/map0/addr", &rmem->address);
if (ret < 0) {
fprintf(stderr, "failed to parse phys_addr of %s\n", path);
saved_errno = -ret;
goto err_unref_dev;
}
ret = parse_hex_sysattr(dev, "maps/map0/size", &rmem->size);
if (ret < 0) {
fprintf(stderr, "failed to parse size of %s\n", path);
saved_errno = -ret;
goto err_unref_dev;
}
rmem->base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (rmem->base == MAP_FAILED) {
saved_errno = errno;
fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
goto err_unref_dev;
}
udev_device_unref(dev);
udev_unref(udev);
return 0;
err_unref_dev:
udev_device_unref(dev);
err_unref_udev:
udev_unref(udev);
err_close_fd:
close(fd);
return -saved_errno;
}
#else
#define PAGE_SIZE 4096
static int rmtfs_mem_open_rfsa(struct rmtfs_mem *rmem, int client_id)
{
int saved_errno;
int fd;
char path[PATH_MAX];
char val[PAGE_SIZE];
char *endptr;
errno = 0;
snprintf(path, sizeof(path), "/dev/qcom_rmtfs_mem%d", client_id);
rmem->fd = open(path, O_RDWR);
if (rmem->fd < 0) {
saved_errno = errno;
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return -saved_errno;
}
snprintf(path, sizeof(path), "/sys/class/rmtfs/qcom_rmtfs_mem%d/phys_addr", client_id);
fd = open(path, O_RDONLY);
if (fd < 0) {
saved_errno = errno;
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return -saved_errno;
}
read(fd, val, sizeof(val));
rmem->address = strtoull(val, &endptr, 16);
if ((rmem->address == ULLONG_MAX && errno == ERANGE) || endptr == val) {
saved_errno = errno;
goto err_close_fd;
}
close(fd);
snprintf(path, sizeof(path), "/sys/class/rmtfs/qcom_rmtfs_mem%d/size", client_id);
fd = open(path, O_RDONLY);
if (fd < 0) {
saved_errno = errno;
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return -saved_errno;
}
read(fd, val, sizeof(val));
rmem->size = strtoull(val, &endptr, 16);
if ((rmem->size == ULLONG_MAX && errno == ERANGE) || endptr == val) {
saved_errno = errno;
goto err_close_fd;
}
close(fd);
return 0;
err_close_fd:
close(fd);
return -saved_errno;
}
static int rmtfs_mem_open_uio(struct rmtfs_mem *rmem, int client_id)
{
fprintf(stderr, "uio access is not supported on ANDROID yet\n");
return -EINVAL;
}
#endif
struct rmtfs_mem *rmtfs_mem_open(void)
{
struct rmtfs_mem *rmem;
@@ -131,26 +282,32 @@ struct rmtfs_mem *rmtfs_mem_open(void)
if (ret < 0 && ret != -ENOENT) {
goto err;
} else if (ret < 0) {
fprintf(stderr, "falling back to /dev/mem access\n");
ret = rmtfs_mem_enumerate(rmem);
if (ret < 0)
fprintf(stderr, "falling back to uio access\n");
ret = rmtfs_mem_open_uio(rmem, 1);
if (ret < 0 && ret != -ENOENT) {
goto err;
} else if (ret < 0) {
fprintf(stderr, "falling back to /dev/mem access\n");
fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd < 0) {
fprintf(stderr, "failed to open /dev/mem\n");
goto err;
ret = rmtfs_mem_enumerate(rmem);
if (ret < 0)
goto err;
fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd < 0) {
fprintf(stderr, "failed to open /dev/mem\n");
goto err;
}
base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, rmem->address);
if (base == MAP_FAILED) {
fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
goto err_close_fd;
}
rmem->base = base;
rmem->fd = fd;
}
base = mmap(0, rmem->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, rmem->address);
if (base == MAP_FAILED) {
fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
goto err_close_fd;
}
rmem->base = base;
rmem->fd = fd;
}
return rmem;
@@ -166,7 +323,7 @@ int64_t rmtfs_mem_alloc(struct rmtfs_mem *rmem, size_t alloc_size)
{
if (alloc_size > rmem->size) {
fprintf(stderr,
"[RMTFS] rmtfs shared memory not large enough for allocation request 0x%zx vs 0x%lx\n",
"[RMTFS] rmtfs shared memory not large enough for allocation request 0x%zx vs %" PRIu64 "\n",
alloc_size, rmem->size);
return -EINVAL;
}
@@ -178,7 +335,7 @@ void rmtfs_mem_free(struct rmtfs_mem *rmem)
{
}
static void *rmtfs_mem_ptr(struct rmtfs_mem *rmem, unsigned phys_address, ssize_t len)
static void *rmtfs_mem_ptr(struct rmtfs_mem *rmem, unsigned long phys_address, ssize_t len)
{
uint64_t start;
uint64_t end;
@@ -192,7 +349,7 @@ static void *rmtfs_mem_ptr(struct rmtfs_mem *rmem, unsigned phys_address, ssize_
if (start < rmem->address || end > rmem->address + rmem->size)
return NULL;
return rmem->base + phys_address - rmem->address;
return (char*)rmem->base + phys_address - rmem->address;
}
ssize_t rmtfs_mem_read(struct rmtfs_mem *rmem, unsigned long phys_address, void *buf, ssize_t len)
@@ -262,7 +419,7 @@ static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem)
if (!dir) {
fprintf(stderr,
"Unable to open reserved-memory device tree node: %s\n",
strerror(-errno));
strerror(errno));
close(basefd);
return -1;
}
@@ -274,7 +431,7 @@ static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem)
dirfd = openat(basefd, de->d_name, O_DIRECTORY);
if (dirfd < 0) {
fprintf(stderr, "failed to open %s: %s\n",
de->d_name, strerror(-errno));
de->d_name, strerror(errno));
ret = -1;
goto out;
}
@@ -282,7 +439,7 @@ static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem)
regfd = openat(dirfd, "reg", O_RDONLY);
if (regfd < 0) {
fprintf(stderr, "failed to open reg of %s: %s\n",
de->d_name, strerror(-errno));
de->d_name, strerror(errno));
ret = -1;
goto out;
}
@@ -296,7 +453,7 @@ static int rmtfs_mem_enumerate(struct rmtfs_mem *rmem)
rmem->size = be64toh(reg.qw[1]);
} else {
fprintf(stderr, "failed to read reg of %s: %s\n",
de->d_name, strerror(-errno));
de->d_name, strerror(errno));
ret = -1;
}

303
storage.c
View File

@@ -1,3 +1,4 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
@@ -8,48 +9,109 @@
#include "rmtfs.h"
#define MAX_CALLERS 10
#define STORAGE_MAX_SIZE (16 * 1024 * 1024)
#define BY_PARTLABEL_PATH "/dev/disk/by-partlabel"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
struct partition {
const char *path;
const char *actual;
const char *partlabel;
};
struct caller {
struct rmtfd {
unsigned id;
unsigned node;
int fd;
unsigned dev_error;
const struct partition *partition;
void *shadow_buf;
size_t shadow_len;
};
static const char *storage_dir = "/boot";
static int storage_read_only;
static int storage_use_partitions;
static const struct partition partition_table[] = {
{ "/boot/modem_fs1", "/boot/modem_fs1" },
{ "/boot/modem_fs2", "/boot/modem_fs2" },
{ "/boot/modem_fsc", "/boot/modem_fsc" },
{ "/boot/modem_fsg", "/boot/modem_fsg" },
{ "/boot/modem_fs1", "modem_fs1", "modemst1" },
{ "/boot/modem_fs2", "modem_fs2", "modemst2" },
{ "/boot/modem_fsc", "modem_fsc", "fsc" },
{ "/boot/modem_fsg", "modem_fsg", "fsg" },
{ "/boot/modem_study", "modem_study", "study" },
{ "/boot/modem_tunning", "modem_tunning", "tunning" },
{ "/boot/modem_tng", "modem_tng", "tunning" },
{}
};
static struct caller caller_handles[MAX_CALLERS];
static struct rmtfd rmtfds[MAX_CALLERS];
int storage_open(void)
static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file);
int storage_init(const char *storage_root, bool read_only, bool use_partitions)
{
int i;
if (storage_root)
storage_dir = storage_root;
if (use_partitions) {
if (!storage_root)
storage_dir = BY_PARTLABEL_PATH;
storage_use_partitions = true;
}
storage_read_only = read_only;
for (i = 0; i < MAX_CALLERS; i++) {
caller_handles[i].id = i;
caller_handles[i].fd = -1;
rmtfds[i].id = i;
rmtfds[i].fd = -1;
rmtfds[i].shadow_buf = NULL;
}
return 0;
}
int storage_get(unsigned node, const char *path)
static int fd_open(struct rmtfd *rmtfd, const char *fspath, const struct partition *part)
{
const struct partition *part;
struct caller *caller = NULL;
int saved_errno;
int ret;
int fd;
if (!storage_read_only) {
fd = open(fspath, O_RDWR);
if (fd < 0) {
saved_errno = errno;
fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
fspath, part->path, strerror(saved_errno));
return saved_errno;
}
rmtfd->fd = fd;
rmtfd->shadow_len = 0;
} else {
ret = storage_populate_shadow_buf(rmtfd, fspath);
if (ret < 0) {
saved_errno = errno;
fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
fspath, part->path, strerror(saved_errno));
return saved_errno;
}
}
return 0;
}
struct rmtfd *storage_open(unsigned node, const char *path, const char *slot_suffix)
{
char *fspath;
const struct partition *part;
struct rmtfd *rmtfd = NULL;
const char *file;
size_t pathlen;
int ret;
int i;
for (part = partition_table; part->path; part++) {
@@ -58,96 +120,197 @@ int storage_get(unsigned node, const char *path)
}
fprintf(stderr, "[RMTFS storage] request for unknown partition '%s', rejecting\n", path);
return -EPERM;
return NULL;
found:
/* Check if this node already has the requested path open */
for (i = 0; i < MAX_CALLERS; i++) {
if (caller_handles[i].fd != -1 &&
caller_handles[i].node == node &&
caller_handles[i].partition == part)
return caller_handles[i].id;
if ((rmtfds[i].fd != -1 || rmtfds[i].shadow_buf) &&
rmtfds[i].node == node &&
rmtfds[i].partition == part)
return &rmtfds[i];
}
for (i = 0; i < MAX_CALLERS; i++) {
if (caller_handles[i].fd == -1) {
caller = &caller_handles[i];
if (rmtfds[i].fd == -1 && !rmtfds[i].shadow_buf) {
rmtfd = &rmtfds[i];
break;
}
}
if (!caller) {
fprintf(stderr, "[storage] out of free caller handles\n");
return -EBUSY;
if (!rmtfd) {
fprintf(stderr, "[storage] out of free rmtfd handles\n");
return NULL;
}
fd = open(part->actual, O_RDWR);
if (fd < 0) {
saved_errno = errno;
fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
part->actual, part->path, strerror(-errno));
return -saved_errno;
if (storage_use_partitions)
file = part->partlabel;
else
file = part->actual;
pathlen = strlen(storage_dir) + strlen(file) + 2 + strnlen(slot_suffix, SLOT_SUFFIX_LEN);
fspath = alloca(pathlen);
snprintf(fspath, pathlen, "%s/%s", storage_dir, file);
ret = fd_open(rmtfd, fspath, part);
if (ret) {
/* Try again with the slot suffix before giving up */
if (!slot_suffix)
return NULL;
snprintf(fspath, pathlen, "%s/%s%s", storage_dir, file, slot_suffix);
ret = fd_open(rmtfd, fspath, part);
if (ret)
return NULL;
}
caller->node = node;
caller->fd = fd;
caller->partition = part;
rmtfd->node = node;
rmtfd->partition = part;
return caller->id;
return rmtfd;
}
int storage_put(unsigned node, int caller_id)
void storage_close(struct rmtfd *rmtfd)
{
struct caller *caller;
if (rmtfd->fd >= 0) {
close(rmtfd->fd);
rmtfd->fd = -1;
}
free(rmtfd->shadow_buf);
rmtfd->shadow_buf = NULL;
rmtfd->shadow_len = 0;
rmtfd->partition = NULL;
}
struct rmtfd *storage_get(unsigned node, int caller_id)
{
struct rmtfd *rmtfd;
if (caller_id >= MAX_CALLERS)
return -EINVAL;
return NULL;
caller = &caller_handles[caller_id];
if (caller->node != node)
return -EINVAL;
rmtfd = &rmtfds[caller_id];
if (rmtfd->node != node)
return NULL;
close(caller->fd);
caller->fd = -1;
caller->partition = NULL;
return 0;
return rmtfd;
}
int storage_get_handle(unsigned node, int caller_id)
int storage_get_caller_id(const struct rmtfd *rmtfd)
{
struct caller *caller;
if (caller_id >= MAX_CALLERS)
return -EINVAL;
caller = &caller_handles[caller_id];
if (caller->node != node)
return -EINVAL;
return caller->fd;
return rmtfd->id;
}
int storage_get_error(unsigned node, int caller_id)
int storage_get_error(const struct rmtfd *rmtfd)
{
struct caller *caller;
if (caller_id >= MAX_CALLERS)
return -EINVAL;
caller = &caller_handles[caller_id];
if (caller->node != node)
return -EINVAL;
return caller->dev_error;
return rmtfd->dev_error;
}
void storage_close(void)
void storage_exit(void)
{
int i;
for (i = 0; i < MAX_CALLERS; i++) {
if (caller_handles[i].fd >= 0)
close(caller_handles[i].fd);
}
for (i = 0; i < MAX_CALLERS; i++)
storage_close(&rmtfds[i]);
}
ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset)
{
ssize_t n;
if (!storage_read_only) {
n = pread(rmtfd->fd, buf, nbyte, offset);
} else {
n = MIN((ssize_t)nbyte, (ssize_t)rmtfd->shadow_len - offset);
if (n > 0)
memcpy(buf, (char*)rmtfd->shadow_buf + offset, n);
else
n = 0;
}
if (n < nbyte)
memset((char*)buf + n, 0, nbyte - n);
return nbyte;
}
ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset)
{
size_t new_len = offset + nbyte;
void *new_buf;
if (!storage_read_only)
return pwrite(rmtfd->fd, buf, nbyte, offset);
if (new_len >= STORAGE_MAX_SIZE) {
fprintf(stderr, "write to %zd bytes exceededs max size\n", new_len);
errno = -EINVAL;
return -1;
}
if (new_len > rmtfd->shadow_len) {
new_buf = realloc(rmtfd->shadow_buf, new_len);
if (!new_buf) {
errno = -ENOMEM;
return -1;
}
rmtfd->shadow_buf = new_buf;
rmtfd->shadow_len = new_len;
}
memcpy((char*)rmtfd->shadow_buf + offset, buf, nbyte);
return nbyte;
}
int storage_sync(struct rmtfd *rmtfd)
{
if (storage_read_only)
return 0;
return fdatasync(rmtfd->fd);
}
static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file)
{
ssize_t len;
ssize_t n;
void *buf;
int ret;
int fd;
fd = open(file, O_RDONLY);
if (fd < 0)
return -1;
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
ret = -1;
goto err_close_fd;
}
lseek(fd, 0, SEEK_SET);
buf = calloc(1, len);
if (!buf) {
ret = -1;
goto err_close_fd;
}
n = read(fd, buf, len);
if (n < 0) {
ret = -1;
goto err_close_fd;
}
rmtfd->shadow_buf = buf;
rmtfd->shadow_len = n;
ret = 0;
err_close_fd:
close(fd);
return ret;
}