aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/Makefile1
-rw-r--r--lib/kernel/doc/src/file.xml12
-rw-r--r--lib/kernel/src/Makefile1
-rw-r--r--lib/kernel/src/code.erl6
-rw-r--r--lib/kernel/src/code_server.erl9
-rw-r--r--lib/kernel/src/file.erl14
-rw-r--r--lib/kernel/src/file_io_server.erl4
-rw-r--r--lib/kernel/src/kernel.app.src1
-rw-r--r--lib/kernel/src/packages.erl158
-rw-r--r--lib/kernel/src/ram_file.erl7
-rw-r--r--lib/kernel/test/Makefile1
-rw-r--r--lib/kernel/test/file_SUITE.erl72
-rw-r--r--lib/kernel/test/heart_SUITE.erl27
-rw-r--r--lib/kernel/test/ignore_cores.erl158
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl74
15 files changed, 368 insertions, 177 deletions
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index 5e04bff0c1..de3ca1e176 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -58,7 +58,6 @@ XML_REF3_FILES = application.xml \
net_adm.xml \
net_kernel.xml \
os.xml \
- packages.xml \
pg2.xml \
rpc.xml \
seq_trace.xml \
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 536b98b5f5..e30ade1bd2 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -170,6 +170,18 @@
</desc>
</func>
<func>
+ <name name="allocate" arity="3"/>
+ <fsummary>Allocate file space</fsummary>
+ <desc>
+ <p><c>allocate/3</c> can be used to preallocate space for a file.</p>
+ <p>This function only succeeds in platforms that implement this
+ feature. When it succeeds, space is preallocated for the file but
+ the file size might not be updated. This behaviour depends on the
+ preallocation implementation. To guarantee the file size is updated
+ one must truncate the file to the new size.</p>
+ </desc>
+ </func>
+ <func>
<name name="change_group" arity="2"/>
<fsummary>Change group of a file</fsummary>
<desc>
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index c76ff9e2f0..60291bbce6 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -107,7 +107,6 @@ MODULES = \
net_adm \
net_kernel \
os \
- packages \
pg2 \
ram_file \
rpc \
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index c808ac7cb7..361f2bdf8a 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -359,7 +359,6 @@ load_code_server_prerequisites() ->
hipe_unified_loader,
lists,
os,
- packages,
unicode],
[M = M:module_info(module) || M <- Needed],
ok.
@@ -413,7 +412,7 @@ which(Module) when is_atom(Module) ->
end.
which2(Module) ->
- Base = to_path(Module),
+ Base = atom_to_list(Module),
File = filename:basename(Base) ++ objfile_extension(),
Path = get_path(),
which(File, filename:dirname(Base), Path).
@@ -547,9 +546,6 @@ has_ext(Ext, Extlen, File) ->
_ -> false
end.
-to_path(X) ->
- filename:join(packages:split(X)).
-
-spec load_native_code_for_all_loaded() -> ok.
load_native_code_for_all_loaded() ->
Architecture = erlang:system_info(hipe_architecture),
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 00ad923466..b2d2c19f78 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1229,7 +1229,7 @@ load_abs(File, Mod0, Caller, St) ->
end.
try_load_module(Mod, Dir, Caller, St) ->
- File = filename:append(Dir, to_path(Mod) ++
+ File = filename:append(Dir, to_list(Mod) ++
objfile_extension()),
case erl_prim_loader:get_file(File) of
error ->
@@ -1347,7 +1347,7 @@ load_file_1(Mod, Caller, #state{cache=Cache}=St0) ->
end.
mod_to_bin([Dir|Tail], Mod) ->
- File = filename:append(Dir, to_path(Mod) ++ objfile_extension()),
+ File = filename:append(Dir, to_list(Mod) ++ objfile_extension()),
case erl_prim_loader:get_file(File) of
error ->
mod_to_bin(Tail, Mod);
@@ -1356,7 +1356,7 @@ mod_to_bin([Dir|Tail], Mod) ->
end;
mod_to_bin([], Mod) ->
%% At last, try also erl_prim_loader's own method
- File = to_path(Mod) ++ objfile_extension(),
+ File = to_list(Mod) ++ objfile_extension(),
case erl_prim_loader:get_file(File) of
error ->
error; % No more alternatives !
@@ -1570,6 +1570,3 @@ to_list(X) when is_atom(X) -> atom_to_list(X).
to_atom(X) when is_atom(X) -> X;
to_atom(X) when is_list(X) -> list_to_atom(X).
-
-to_path(X) ->
- filename:join(packages:split(X)).
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index de3eaad5a1..16f2dde464 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -38,7 +38,7 @@
%% Specialized
-export([ipread_s32bu_p32bu/3]).
%% Generic file contents.
--export([open/2, close/1, advise/4,
+-export([open/2, close/1, advise/4, allocate/3,
read/2, write/2,
pread/2, pread/3, pwrite/2, pwrite/3,
read_line/1,
@@ -490,6 +490,18 @@ advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
advise(_, _, _, _) ->
{error, badarg}.
+-spec allocate(File, Offset, Length) ->
+ 'ok' | {'error', posix()} when
+ File :: io_device(),
+ Offset :: non_neg_integer(),
+ Length :: non_neg_integer().
+
+allocate(File, Offset, Length) when is_pid(File) ->
+ R = file_request(File, {allocate, Offset, Length}),
+ wait_file_reply(File, R);
+allocate(#file_descriptor{module = Module} = Handle, Offset, Length) ->
+ Module:allocate(Handle, Offset, Length).
+
-spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when
IoDevice :: io_device() | atom(),
Number :: non_neg_integer(),
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index acaffe1e41..fad2ed7fb3 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -211,6 +211,10 @@ file_request({advise,Offset,Length,Advise},
Reply ->
{reply,Reply,State}
end;
+file_request({allocate, Offset, Length},
+ #state{handle = Handle} = State) ->
+ Reply = ?PRIM_FILE:allocate(Handle, Offset, Length),
+ {reply, Reply, State};
file_request({pread,At,Sz},
#state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
case position(Handle, At, Buf) of
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 17ab84c177..9a20baf8d0 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -28,7 +28,6 @@
application_starter,
auth,
code,
- packages,
code_server,
dist_util,
erl_boot_server,
diff --git a/lib/kernel/src/packages.erl b/lib/kernel/src/packages.erl
deleted file mode 100644
index e0b1f36b85..0000000000
--- a/lib/kernel/src/packages.erl
+++ /dev/null
@@ -1,158 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(packages).
-
--export([to_string/1, concat/1, concat/2, is_valid/1, is_segmented/1,
- split/1, last/1, first/1, strip_last/1, find_modules/1,
- find_modules/2]).
-
-%% A package name (or a package-qualified module name) may be an atom or
-%% a string (list of nonnegative integers) - not a deep list, and not a
-%% list containing atoms. A name may be empty, but may not contain two
-%% consecutive period (`.') characters or end with a period character.
-
--type package_name() :: atom() | string().
-
--spec to_string(package_name()) -> string().
-to_string(Name) when is_atom(Name) ->
- atom_to_list(Name);
-to_string(Name) ->
- Name.
-
-%% `concat' does not insert a leading period if the first segment is
-%% empty. However, the result may contain leading, consecutive or
-%% dangling period characters, if any of the segments after the first
-%% are empty. Use 'is_valid' to check the result if necessary.
-
--spec concat(package_name(), package_name()) -> string().
-concat(A, B) ->
- concat([A, B]).
-
--spec concat([package_name()]) -> string().
-concat([H | T]) when is_atom(H) ->
- concat([atom_to_list(H) | T]);
-concat(["" | T]) ->
- concat_1(T);
-concat(L) ->
- concat_1(L).
-
-concat_1([H | T]) when is_atom(H) ->
- concat_1([atom_to_list(H) | T]);
-concat_1([H]) ->
- H;
-concat_1([H | T]) ->
- H ++ "." ++ concat_1(T);
-concat_1([]) ->
- "";
-concat_1(Name) ->
- erlang:error({badarg, Name}).
-
--spec is_valid(package_name()) -> boolean().
-is_valid(Name) when is_atom(Name) ->
- is_valid_1(atom_to_list(Name));
-is_valid([$. | _]) ->
- false;
-is_valid(Name) ->
- is_valid_1(Name).
-
-is_valid_1([$.]) -> false;
-is_valid_1([$., $. | _]) -> false;
-is_valid_1([H | T]) when is_integer(H), H >= 0 ->
- is_valid_1(T);
-is_valid_1([]) -> true;
-is_valid_1(_) -> false.
-
--spec split(package_name()) -> [string()].
-split(Name) when is_atom(Name) ->
- split_1(atom_to_list(Name), []);
-split(Name) ->
- split_1(Name, []).
-
-split_1([$. | T], Cs) ->
- [lists:reverse(Cs) | split_1(T, [])];
-split_1([H | T], Cs) when is_integer(H), H >= 0 ->
- split_1(T, [H | Cs]);
-split_1([], Cs) ->
- [lists:reverse(Cs)];
-split_1(_, _) ->
- erlang:error(badarg).
-
-%% This is equivalent to testing if `split(Name)' yields a list of
-%% length larger than one (i.e., if the name can be split into two or
-%% more segments), but is cheaper.
-
--spec is_segmented(package_name()) -> boolean().
-is_segmented(Name) when is_atom(Name) ->
- is_segmented_1(atom_to_list(Name));
-is_segmented(Name) ->
- is_segmented_1(Name).
-
-is_segmented_1([$. | _]) -> true;
-is_segmented_1([H | T]) when is_integer(H), H >= 0 ->
- is_segmented_1(T);
-is_segmented_1([]) -> false;
-is_segmented_1(_) ->
- erlang:error(badarg).
-
--spec last(package_name()) -> string().
-last(Name) ->
- last_1(split(Name)).
-
-last_1([H]) -> H;
-last_1([_ | T]) -> last_1(T).
-
--spec first(package_name()) -> [string()].
-first(Name) ->
- first_1(split(Name)).
-
-first_1([H | T]) when T =/= [] -> [H | first_1(T)];
-first_1(_) -> [].
-
--spec strip_last(package_name()) -> string().
-strip_last(Name) ->
- concat(first(Name)).
-
-%% This finds all modules available for a given package, using the
-%% current code server search path. (There is no guarantee that the
-%% modules are loadable; only that the object files exist.)
-
--spec find_modules(package_name()) -> [string()].
-find_modules(P) ->
- find_modules(P, code:get_path()).
-
--spec find_modules(package_name(), [string()]) -> [string()].
-find_modules(P, Paths) ->
- P1 = filename:join(packages:split(P)),
- find_modules(P1, Paths, code:objfile_extension(), sets:new()).
-
-find_modules(P, [Path | Paths], Ext, S0) ->
- case file:list_dir(filename:join(Path, P)) of
- {ok, Fs} ->
- Fs1 = [F || F <- Fs, filename:extension(F) =:= Ext],
- S1 = lists:foldl(fun (F, S) ->
- F1 = filename:rootname(F, Ext),
- sets:add_element(F1, S)
- end,
- S0, Fs1),
- find_modules(P, Paths, Ext, S1);
- _ ->
- find_modules(P, Paths, Ext, S0)
- end;
-find_modules(_P, [], _Ext, S) ->
- sets:to_list(S).
diff --git a/lib/kernel/src/ram_file.erl b/lib/kernel/src/ram_file.erl
index 48ea871433..ca881ff8a4 100644
--- a/lib/kernel/src/ram_file.erl
+++ b/lib/kernel/src/ram_file.erl
@@ -29,6 +29,7 @@
%% Specialized file operations
-export([get_size/1, get_file/1, set_file/2, get_file_close/1]).
-export([compress/1, uncompress/1, uuencode/1, uudecode/1, advise/4]).
+-export([allocate/3]).
-export([open_mode/1]). %% used by ftp-file
@@ -72,6 +73,7 @@
-define(RAM_FILE_UUDECODE, 36).
-define(RAM_FILE_SIZE, 37).
-define(RAM_FILE_ADVISE, 38).
+-define(RAM_FILE_ALLOCATE, 39).
%% Open modes for RAM_FILE_OPEN
-define(RAM_FILE_MODE_READ, 1).
@@ -383,6 +385,11 @@ advise(#file_descriptor{module = ?MODULE, data = Port}, Offset,
advise(#file_descriptor{}, _Offset, _Length, _Advise) ->
{error, enotsup}.
+allocate(#file_descriptor{module = ?MODULE, data = Port}, Offset, Length) ->
+ call_port(Port, <<?RAM_FILE_ALLOCATE, Offset:64/signed, Length:64/signed>>);
+allocate(#file_descriptor{}, _Offset, _Length) ->
+ {error, enotsup}.
+
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 8eca37029d..7fd3afe93c 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -73,6 +73,7 @@ MODULES= \
seq_trace_SUITE \
wrap_log_reader_SUITE \
cleanup \
+ ignore_cores \
zlib_SUITE \
loose_node \
sendfile_SUITE
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 9c507fd437..914f0d6127 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -84,6 +84,8 @@
-export([advise/1]).
+-export([allocate/1]).
+
-export([standard_io/1,mini_server/1]).
%% Debug exports
@@ -116,7 +118,7 @@ groups() ->
{files, [],
[{group, open}, {group, pos}, {group, file_info},
{group, consult}, {group, eval}, {group, script},
- truncate, sync, datasync, advise]},
+ truncate, sync, datasync, advise, allocate]},
{open, [],
[open1, old_modes, new_modes, path_open, close, access,
read_write, pread_write, append, open_errors,
@@ -1617,6 +1619,74 @@ advise(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+allocate(suite) -> [];
+allocate(doc) -> "Tests that ?FILE_MODULE:allocate/3 at least doesn't crash.";
+allocate(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Allocate = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_allocate.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])),
+ ?line ok = io:format(Fd, "~s", [Line1]),
+ ?line ok = io:format(Fd, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd),
+
+ ?line {ok, Fd2} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd2, 1, iolist_size(Line1)),
+ ?line ok = io:format(Fd2, "~s", [Line1]),
+ ?line ok = io:format(Fd2, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd2),
+
+ ?line {ok, Fd3} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1),
+ ?line ok = io:format(Fd3, "~s", [Line1]),
+ ?line ok = io:format(Fd3, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd3),
+
+ ?line {ok, Fd4} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])),
+ ?line ok = io:format(Fd4, "~s", [Line1]),
+ ?line ok = io:format(Fd4, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd4),
+
+ ?line [] = flush(),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+allocate_and_assert(Fd, Offset, Length) ->
+ % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have
+ % any other negative side effect. We can't really asssert against a
+ % specific return value, because support for file space pre-allocation
+ % depends on the OS, OS version and underlying filesystem.
+ %
+ % The Linux kernel added support for fallocate() in version 2.6.23,
+ % which currently works only for the ext4, ocfs2, xfs and btrfs file
+ % systems. posix_fallocate() is available in glibc as of version
+ % 2.1.94, but it was buggy until glibc version 2.7.
+ %
+ % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE.
+ %
+ % Solaris supports posix_fallocate() but only for the UFS file system
+ % apparently (not supported for ZFS).
+ %
+ % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate().
+ %
+ % For Windows there's apparently no way to pre-allocate file space, at
+ % least with same semantics as posix_fallocate(), fallocate() and
+ % fcntl F_PREALLOCATE.
+ Result = ?FILE_MODULE:allocate(Fd, Offset, Length),
+ case os:type() of
+ {win32, _} ->
+ ?line {error, enotsup} = Result;
+ _ ->
+ ?line _ = Result
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 2ec3b7c297..320b23bea1 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -83,10 +83,10 @@ init_per_suite(Config) when is_list(Config) ->
{win32, windows} ->
{skipped, "No use to run on Windows 95/98"};
_ ->
- Config
+ ignore_cores:init(Config)
end.
end_per_suite(Config) when is_list(Config) ->
- Config.
+ ignore_cores:fini(Config).
start_check(Type, Name) ->
@@ -188,8 +188,20 @@ reboot(Config) when is_list(Config) ->
%% Check that a node is up and running after a crash.
%% This test exhausts the atom table on the remote node.
%% ERL_CRASH_DUMP_SECONDS=0 will force beam not to dump an erl_crash.dump.
+%% May currently dump core in beam debug build due to lock-order violation
+%% This should be removed when a non-lockad information retriever is implemented
+%% for crash dumps
node_start_immediately_after_crash(suite) -> {req, [{time, 10}]};
node_start_immediately_after_crash(Config) when is_list(Config) ->
+ Config2 = ignore_cores:setup(?MODULE, node_start_immediately_after_crash, Config, true),
+ try
+ node_start_immediately_after_crash_test(Config2)
+ after
+ ignore_cores:restore(Config2)
+ end.
+
+
+node_start_immediately_after_crash_test(Config) when is_list(Config) ->
{ok, Node} = start_check(loose, heart_test_imm, [{"ERL_CRASH_DUMP_SECONDS", "0"}]),
ok = rpc:call(Node, heart, set_cmd,
@@ -228,8 +240,19 @@ node_start_immediately_after_crash(Config) when is_list(Config) ->
%% This test exhausts the atom table on the remote node.
%% ERL_CRASH_DUMP_SECONDS=10 will force beam
%% to only dump an erl_crash.dump for 10 seconds.
+%% May currently dump core in beam debug build due to lock-order violation
+%% This should be removed when a non-lockad information retriever is implemented
+%% for crash dumps
node_start_soon_after_crash(suite) -> {req, [{time, 10}]};
node_start_soon_after_crash(Config) when is_list(Config) ->
+ Config2 = ignore_cores:setup(?MODULE, node_start_soon_after_crash, Config, true),
+ try
+ node_start_soon_after_crash_test(Config2)
+ after
+ ignore_cores:restore(Config2)
+ end.
+
+node_start_soon_after_crash_test(Config) when is_list(Config) ->
{ok, Node} = start_check(loose, heart_test_soon, [{"ERL_CRASH_DUMP_SECONDS", "10"}]),
ok = rpc:call(Node, heart, set_cmd,
diff --git a/lib/kernel/test/ignore_cores.erl b/lib/kernel/test/ignore_cores.erl
new file mode 100644
index 0000000000..8b1ac0fe6c
--- /dev/null
+++ b/lib/kernel/test/ignore_cores.erl
@@ -0,0 +1,158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : ignore_cores.erl
+%%% Author : Rickard Green <[email protected]>
+%%% Description :
+%%%
+%%% Created : 11 Feb 2008 by Rickard Green <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(ignore_cores).
+
+-include_lib("test_server/include/test_server.hrl").
+
+-export([init/1, fini/1, setup/3, setup/4, restore/1, dir/1]).
+
+-record(ignore_cores, {org_cwd,
+ org_path,
+ org_pwd_env,
+ ign_dir = false,
+ cores_dir = false}).
+
+%%
+%% Takes a testcase config
+%%
+
+init(Config) ->
+ {ok, OrgCWD} = file:get_cwd(),
+ [{ignore_cores,
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = code:get_path(),
+ org_pwd_env = os:getenv("PWD")}}
+ | lists:keydelete(ignore_cores, 1, Config)].
+
+fini(Config) ->
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD} = ?config(ignore_cores, Config),
+ ok = file:set_cwd(OrgCWD),
+ true = code:set_path(OrgPath),
+ case OrgPWD of
+ false -> ok;
+ _ -> true = os:putenv("PWD", OrgPWD)
+ end,
+ lists:keydelete(ignore_cores, 1, Config).
+
+setup(Suite, Testcase, Config) ->
+ setup(Suite, Testcase, Config, false).
+
+setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite),
+ is_atom(Testcase),
+ is_list(Config) ->
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD} = ?config(ignore_cores, Config),
+ Path = lists:map(fun (".") -> OrgCWD; (Dir) -> Dir end, OrgPath),
+ true = code:set_path(Path),
+ PrivDir = ?config(priv_dir, Config),
+ IgnDir = filename:join([PrivDir,
+ atom_to_list(Suite)
+ ++ "_"
+ ++ atom_to_list(Testcase)
+ ++ "_wd"]),
+ ok = file:make_dir(IgnDir),
+ case SetCwd of
+ false ->
+ ok;
+ _ ->
+ ok = file:set_cwd(IgnDir),
+ OrgPWD = case os:getenv("PWD") of
+ false -> false;
+ PWD ->
+ os:putenv("PWD", IgnDir),
+ PWD
+ end
+ end,
+ ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>),
+ %% cores are dumped in /cores on MacOS X
+ CoresDir = case {?t:os_type(), filelib:is_dir("/cores")} of
+ {{unix,darwin}, true} ->
+ filelib:fold_files("/cores",
+ "^core.*$",
+ false,
+ fun (C,Cs) -> [C|Cs] end,
+ []);
+ _ ->
+ false
+ end,
+ lists:keyreplace(ignore_cores,
+ 1,
+ Config,
+ {ignore_cores,
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD,
+ ign_dir = IgnDir,
+ cores_dir = CoresDir}}).
+
+restore(Config) ->
+ #ignore_cores{org_cwd = OrgCWD,
+ org_path = OrgPath,
+ org_pwd_env = OrgPWD,
+ ign_dir = IgnDir,
+ cores_dir = CoresDir} = ?config(ignore_cores, Config),
+ try
+ case CoresDir of
+ false ->
+ ok;
+ _ ->
+ %% Move cores dumped by these testcases in /cores
+ %% to cwd.
+ lists:foreach(fun (C) ->
+ case lists:member(C, CoresDir) of
+ true -> ok;
+ _ ->
+ Dst = filename:join(
+ [IgnDir,
+ filename:basename(C)]),
+ {ok, _} = file:copy(C, Dst),
+ file:delete(C)
+ end
+ end,
+ filelib:fold_files("/cores",
+ "^core.*$",
+ false,
+ fun (C,Cs) -> [C|Cs] end,
+ []))
+ end
+ after
+ catch file:set_cwd(OrgCWD),
+ catch code:set_path(OrgPath),
+ case OrgPWD of
+ false -> ok;
+ _ -> catch os:putenv("PWD", OrgPWD)
+ end
+ end.
+
+
+dir(Config) ->
+ #ignore_cores{ign_dir = Dir} = ?config(ignore_cores, Config),
+ Dir.
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index a56746bbc4..4e93a593b3 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -57,6 +57,8 @@
%% System probe functions that might be handy to check from the shell
-export([unix_free/1]).
+-export([allocate/1]).
+
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -87,7 +89,7 @@ groups() ->
cur_dir_1a, cur_dir_1b]},
{files, [],
[{group, open}, {group, pos}, {group, file_info},
- truncate, sync, datasync, advise, large_write]},
+ truncate, sync, datasync, advise, large_write, allocate]},
{open, [],
[open1, modes, close, access, read_write, pread_write,
append, exclusive]},
@@ -1359,6 +1361,76 @@ check_large_write(Dog, Fd, _, _, []) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allocate(suite) -> [];
+allocate(doc) -> "Tests that ?PRIM_FILE:allocate/3 at least doesn't crash.";
+allocate(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Allocate = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_allocate.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])),
+ ?line ok = ?PRIM_FILE:write(Fd, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd),
+
+ ?line {ok, Fd2} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd2, 1, iolist_size(Line1)),
+ ?line ok = ?PRIM_FILE:write(Fd2, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd2, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd2),
+
+ ?line {ok, Fd3} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1),
+ ?line ok = ?PRIM_FILE:write(Fd3, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd3, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd3),
+
+ ?line {ok, Fd4} = ?PRIM_FILE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])),
+ ?line ok = ?PRIM_FILE:write(Fd4, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd4, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd4),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+allocate_and_assert(Fd, Offset, Length) ->
+ % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have
+ % any other negative side effect. We can't really asssert against a
+ % specific return value, because support for file space pre-allocation
+ % depends on the OS, OS version and underlying filesystem.
+ %
+ % The Linux kernel added support for fallocate() in version 2.6.23,
+ % which currently works only for the ext4, ocfs2, xfs and btrfs file
+ % systems. posix_fallocate() is available in glibc as of version
+ % 2.1.94, but it was buggy until glibc version 2.7.
+ %
+ % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE.
+ %
+ % Solaris supports posix_fallocate() but only for the UFS file system
+ % apparently (not supported for ZFS).
+ %
+ % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate().
+ %
+ % For Windows there's apparently no way to pre-allocate file space, at
+ % least with similar API/semantics as posix_fallocate(), fallocate() or
+ % fcntl F_PREALLOCATE.
+ Result = ?PRIM_FILE:allocate(Fd, Offset, Length),
+ case os:type() of
+ {win32, _} ->
+ ?line {error, enotsup} = Result;
+ _ ->
+ ?line _ = Result
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
delete_a(suite) -> [];
delete_a(doc) -> [];
delete_a(Config) when is_list(Config) ->