mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-28 01:28:53 +00:00
VFS, File_system: Not_empty
Unlink returns an error for non-empty directories when the backend does not support recursive unlinking. Fixes #1750
This commit is contained in:
parent
5bc3b53e63
commit
1d92631ef0
repos
libports/src/lib/libc
os
include
src/test/vfs_stress
ports/src/lib/libc_noux
@ -762,9 +762,10 @@ int Libc::Vfs_plugin::unlink(char const *path)
|
||||
typedef Vfs::Directory_service::Unlink_result Result;
|
||||
|
||||
switch (_root_dir.unlink(path)) {
|
||||
case Result::UNLINK_ERR_NO_ENTRY: errno = ENOENT; return -1;
|
||||
case Result::UNLINK_ERR_NO_PERM: errno = EPERM; return -1;
|
||||
case Result::UNLINK_OK: break;
|
||||
case Result::UNLINK_ERR_NO_ENTRY: errno = ENOENT; return -1;
|
||||
case Result::UNLINK_ERR_NO_PERM: errno = EPERM; return -1;
|
||||
case Result::UNLINK_ERR_NOT_EMPTY: errno = ENOTEMPTY; return -1;
|
||||
case Result::UNLINK_OK: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ namespace File_system {
|
||||
class Invalid_handle : Exception { };
|
||||
class Invalid_name : Exception { };
|
||||
class Size_limit_reached : Exception { };
|
||||
class Not_empty : Exception { };
|
||||
|
||||
struct Session;
|
||||
}
|
||||
@ -275,6 +276,12 @@ struct File_system::Session : public Genode::Session
|
||||
|
||||
/**
|
||||
* Delete file or directory
|
||||
*
|
||||
* \throw Permission_denied
|
||||
* \throw Invalid_name
|
||||
* \throw Lookup_failed
|
||||
* \throw Not_empty argument is a non-empty directory and
|
||||
* the backend does not support recursion
|
||||
*/
|
||||
virtual void unlink(Dir_handle, Name const &) = 0;
|
||||
|
||||
@ -336,7 +343,8 @@ struct File_system::Session : public Genode::Session
|
||||
GENODE_RPC(Rpc_status, Status, status, Node_handle);
|
||||
GENODE_RPC(Rpc_control, void, control, Node_handle, Control);
|
||||
GENODE_RPC_THROW(Rpc_unlink, void, unlink,
|
||||
GENODE_TYPE_LIST(Permission_denied, Invalid_name, Lookup_failed),
|
||||
GENODE_TYPE_LIST(Permission_denied, Invalid_name,
|
||||
Lookup_failed, Not_empty),
|
||||
Dir_handle, Name const &);
|
||||
GENODE_RPC_THROW(Rpc_truncate, void, truncate,
|
||||
GENODE_TYPE_LIST(Permission_denied, Invalid_handle, No_space),
|
||||
|
@ -121,7 +121,8 @@ struct Vfs::Directory_service
|
||||
** Unlink **
|
||||
************/
|
||||
|
||||
enum Unlink_result { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM, UNLINK_OK };
|
||||
enum Unlink_result { UNLINK_ERR_NO_ENTRY, UNLINK_ERR_NO_PERM,
|
||||
UNLINK_ERR_NOT_EMPTY, UNLINK_OK };
|
||||
|
||||
virtual Unlink_result unlink(char const *path) = 0;
|
||||
|
||||
|
@ -349,8 +349,9 @@ class Vfs::Fs_file_system : public File_system
|
||||
|
||||
_fs.unlink(dir, file_name.base() + 1);
|
||||
}
|
||||
catch (::File_system::Permission_denied) { return UNLINK_ERR_NO_PERM; }
|
||||
catch (...) { return UNLINK_ERR_NO_ENTRY; }
|
||||
catch (::File_system::Permission_denied) { return UNLINK_ERR_NO_PERM; }
|
||||
catch (::File_system::Not_empty) { return UNLINK_ERR_NOT_EMPTY; }
|
||||
catch (...) { return UNLINK_ERR_NO_ENTRY; }
|
||||
|
||||
return UNLINK_OK;
|
||||
}
|
||||
|
@ -130,6 +130,8 @@ inline void assert_unlink(Vfs::Directory_service::Unlink_result r)
|
||||
PERR("UNLINK_ERR_NO_ENTRY"); break;
|
||||
case Result::UNLINK_ERR_NO_PERM:
|
||||
PERR("UNLINK_ERR_NO_PERM"); break;
|
||||
case Result::UNLINK_ERR_NOT_EMPTY:
|
||||
PERR("UNLINK_ERR_NOT_EMPTY"); break;
|
||||
}
|
||||
throw Exception();
|
||||
}
|
||||
@ -145,15 +147,18 @@ struct Stress_thread : public Genode::Thread<4*1024*sizeof(Genode::addr_t)>
|
||||
Vfs::file_size count;
|
||||
Vfs::File_system &vfs;
|
||||
|
||||
Stress_thread(Vfs::File_system &vfs, char const *parent)
|
||||
: Thread(parent), path(parent), count(0), vfs(vfs) { }
|
||||
Stress_thread(Vfs::File_system &vfs, char const *parent, Affinity::Location affinity)
|
||||
: Thread(parent), path(parent), count(0), vfs(vfs)
|
||||
{
|
||||
env()->cpu_session()->affinity(cap(), affinity);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Mkdir_thread : public Stress_thread
|
||||
{
|
||||
Mkdir_thread(Vfs::File_system &vfs, char const *parent)
|
||||
: Stress_thread(vfs, parent) { start(); }
|
||||
Mkdir_thread(Vfs::File_system &vfs, char const *parent, Affinity::Location affinity)
|
||||
: Stress_thread(vfs, parent, affinity) { start(); }
|
||||
|
||||
void mkdir_b(int depth)
|
||||
{
|
||||
@ -201,8 +206,8 @@ struct Mkdir_thread : public Stress_thread
|
||||
|
||||
struct Populate_thread : public Stress_thread
|
||||
{
|
||||
Populate_thread(Vfs::File_system &vfs, char const *parent)
|
||||
: Stress_thread(vfs, parent) { start(); }
|
||||
Populate_thread(Vfs::File_system &vfs, char const *parent, Affinity::Location affinity)
|
||||
: Stress_thread(vfs, parent, affinity) { start(); }
|
||||
|
||||
|
||||
void populate(int depth)
|
||||
@ -266,8 +271,8 @@ struct Populate_thread : public Stress_thread
|
||||
|
||||
struct Write_thread : public Stress_thread
|
||||
{
|
||||
Write_thread(Vfs::File_system &vfs, char const *parent)
|
||||
: Stress_thread(vfs, parent) { start(); }
|
||||
Write_thread(Vfs::File_system &vfs, char const *parent, Affinity::Location affinity)
|
||||
: Stress_thread(vfs, parent, affinity) { start(); }
|
||||
|
||||
void write(int depth)
|
||||
{
|
||||
@ -334,8 +339,8 @@ struct Write_thread : public Stress_thread
|
||||
|
||||
struct Read_thread : public Stress_thread
|
||||
{
|
||||
Read_thread(Vfs::File_system &vfs, char const *parent)
|
||||
: Stress_thread(vfs, parent) { start(); }
|
||||
Read_thread(Vfs::File_system &vfs, char const *parent, Affinity::Location affinity)
|
||||
: Stress_thread(vfs, parent, affinity) { start(); }
|
||||
|
||||
void read(int depth)
|
||||
{
|
||||
@ -404,8 +409,8 @@ struct Read_thread : public Stress_thread
|
||||
|
||||
struct Unlink_thread : public Stress_thread
|
||||
{
|
||||
Unlink_thread(Vfs::File_system &vfs, char const *parent)
|
||||
: Stress_thread(vfs, parent) { start(); }
|
||||
Unlink_thread(Vfs::File_system &vfs, char const *parent, Affinity::Location affinity)
|
||||
: Stress_thread(vfs, parent, affinity) { start(); }
|
||||
|
||||
void empty_dir(char const *path)
|
||||
{
|
||||
@ -427,6 +432,7 @@ struct Unlink_thread : public Stress_thread
|
||||
default:
|
||||
try {
|
||||
assert_unlink(vfs.unlink(subpath.base()));
|
||||
++count;
|
||||
} catch (...) {
|
||||
PERR("unlink %s failed", subpath.base());
|
||||
throw;
|
||||
@ -438,10 +444,32 @@ struct Unlink_thread : public Stress_thread
|
||||
|
||||
void entry()
|
||||
{
|
||||
typedef Vfs::Directory_service::Unlink_result Result;
|
||||
try {
|
||||
empty_dir(path.base());
|
||||
vfs.unlink(path.base());
|
||||
} catch (...) { }
|
||||
Result r = vfs.unlink(path.base());
|
||||
switch (r) {
|
||||
case Result::UNLINK_ERR_NOT_EMPTY:
|
||||
PLOG("recursive unlink not supported");
|
||||
empty_dir(path.base());
|
||||
r = vfs.unlink(path.base());
|
||||
|
||||
case Result::UNLINK_OK:
|
||||
PLOG("recursive unlink supported");
|
||||
++count;
|
||||
return;
|
||||
|
||||
default: break;
|
||||
}
|
||||
assert_unlink(r);
|
||||
} catch (...) {
|
||||
PERR("unlink %s failed", path.base());
|
||||
}
|
||||
}
|
||||
|
||||
int wait()
|
||||
{
|
||||
join();
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
@ -468,6 +496,8 @@ int main()
|
||||
/* populate the directory file system at / */
|
||||
vfs_root.num_dirent("/");
|
||||
|
||||
Affinity::Space space = env()->cpu_session()->affinity_space();
|
||||
|
||||
size_t initial_consumption = env()->ram_session()->used();
|
||||
|
||||
/**************************
|
||||
@ -483,7 +513,7 @@ int main()
|
||||
snprintf(path, 3, "/%lu", i);
|
||||
vfs_root.mkdir(path, 0);
|
||||
threads[i] = new (Genode::env()->heap())
|
||||
Mkdir_thread(vfs_root, path);
|
||||
Mkdir_thread(vfs_root, path, space.location_of_index(i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
@ -510,9 +540,8 @@ int main()
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
snprintf(path, 3, "/%lu", i);
|
||||
vfs_root.mkdir(path, 0);
|
||||
threads[i] = new (Genode::env()->heap())
|
||||
Populate_thread(vfs_root, path);
|
||||
Populate_thread(vfs_root, path, space.location_of_index(i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
@ -549,9 +578,8 @@ int main()
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
snprintf(path, 3, "/%lu", i);
|
||||
vfs_root.mkdir(path, 0);
|
||||
threads[i] = new (Genode::env()->heap())
|
||||
Write_thread(vfs_root, path);
|
||||
Write_thread(vfs_root, path, space.location_of_index(i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
@ -588,9 +616,8 @@ int main()
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
snprintf(path, 3, "/%lu", i);
|
||||
vfs_root.mkdir(path, 0);
|
||||
threads[i] = new (Genode::env()->heap())
|
||||
Read_thread(vfs_root, path);
|
||||
Read_thread(vfs_root, path, space.location_of_index(i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
@ -620,19 +647,20 @@ int main()
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
Vfs::file_size count = 0;
|
||||
|
||||
Unlink_thread *threads[thread_count];
|
||||
PLOG("unlink files...");
|
||||
elapsed_ms = timer.elapsed_ms();
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
snprintf(path, 3, "/%lu", i);
|
||||
vfs_root.mkdir(path, 0);
|
||||
threads[i] = new (Genode::env()->heap())
|
||||
Unlink_thread(vfs_root, path);
|
||||
Unlink_thread(vfs_root, path, space.location_of_index(i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i) {
|
||||
threads[i]->join();
|
||||
count += threads[i]->wait();
|
||||
destroy(Genode::env()->heap(), threads[i]);
|
||||
}
|
||||
|
||||
@ -640,8 +668,8 @@ int main()
|
||||
|
||||
vfs_root.sync("/");
|
||||
|
||||
PINF("unlink in %lums, %luKB consumed",
|
||||
elapsed_ms, env()->ram_session()->used()/1024);
|
||||
PINF("unlinked %llu files in %lums, %luKB consumed",
|
||||
count, elapsed_ms, env()->ram_session()->used()/1024);
|
||||
}
|
||||
|
||||
PINF("total: %lums, %luKB consumed",
|
||||
|
@ -1634,9 +1634,12 @@ namespace {
|
||||
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_UNLINK)) {
|
||||
PWRN("unlink syscall failed for path \"%s\"", path);
|
||||
typedef Vfs::Directory_service::Unlink_result Result;
|
||||
switch (sysio()->error.unlink) {
|
||||
case Vfs::Directory_service::UNLINK_ERR_NO_ENTRY: errno = ENOENT; break;
|
||||
default: errno = EPERM; break;
|
||||
case Result::UNLINK_ERR_NO_ENTRY: errno = ENOENT; break;
|
||||
case Result::UNLINK_ERR_NOT_EMPTY: errno = ENOTEMPTY; break;
|
||||
case Result::UNLINK_ERR_NO_PERM: errno = EPERM; break;
|
||||
case Result::UNLINK_OK: break; /* only here to complete the enumeration */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user