Skip to content
Browse files

Added file:allocate/3. This function allocates space for a file.

It only has effect in POSIX platforms that implement the posix_fallocate system call.
  • Loading branch information...
1 parent 4101091 commit ea3dfb992c769a7d47de1892284b125212d13179 @fdmanana fdmanana committed Dec 1, 2010
View
32 erts/configure.in
@@ -1092,6 +1092,38 @@ AC_SUBST(ERTS_BUILD_SMP_EMU)
AC_CHECK_FUNCS([posix_fadvise])
+dnl * Old glibcs have broken posix_fallocate(). Make sure not to use it.
+dnl * It may also be broken in AIX.
+AC_CACHE_CHECK([whether posix_fallocate() works],i_cv_posix_fallocate_works,[
+ AC_TRY_RUN([
+ #define _XOPEN_SOURCE 600
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #if defined(__GLIBC__) && (__GLIBC__ < 2 || __GLIBC_MINOR__ < 7)
+ possibly broken posix_fallocate
+ #endif
+ int main() {
+ int fd = creat("conftest.temp", 0600);
+ int ret;
+ if (fd == -1) {
+ perror("creat()");
+ return 2;
+ }
+ ret = posix_fallocate(fd, 1024, 1024) < 0 ? 1 : 0;
+ unlink("conftest.temp");
+ return ret;
+ }
+ ], [
+ i_cv_posix_fallocate_works=yes
+ ], [
+ i_cv_posix_fallocate_works=no
+ ])
+])
+if test $i_cv_posix_fallocate_works = yes; then
+ AC_DEFINE(HAVE_POSIX_FALLOCATE,, Define if you have a working posix_fallocate())
+fi
#
# Figure out if the emulator should use threads. The default is set above
View
31 erts/emulator/drivers/common/efile_drv.c
@@ -55,6 +55,7 @@
#define FILE_READ_LINE 29
#define FILE_FDATASYNC 30
#define FILE_FADVISE 31
+#define FILE_FALLOCATE 32
/* Return codes */
@@ -364,6 +365,10 @@ struct t_data
Sint64 length;
int advise;
} fadvise;
+ struct {
+ Sint64 offset;
+ Sint64 length;
+ } fallocate;
} c;
char b[1];
};
@@ -1665,6 +1670,17 @@ static void invoke_fadvise(void *data)
d->result_ok = efile_fadvise(&d->errInfo, fd, offset, length, advise);
}
+static void invoke_fallocate(void *data)
+{
+ struct t_data *d = (struct t_data *) data;
+ int fd = (int) d->fd;
+ off_t offset = (off_t) d->c.fallocate.offset;
+ off_t length = (off_t) d->c.fallocate.length;
+
+ d->again = 0;
+ d->result_ok = efile_fallocate(&d->errInfo, fd, offset, length);
+}
+
static void free_readdir(void *data)
{
struct t_data *d = (struct t_data *) data;
@@ -1955,6 +1971,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
case FILE_RENAME:
case FILE_WRITE_INFO:
case FILE_FADVISE:
+ case FILE_FALLOCATE:
reply(desc, d->result_ok, &d->errInfo);
free_data(data);
break;
@@ -2389,6 +2406,20 @@ file_output(ErlDrvData e, char* buf, int count)
goto done;
}
+ case FILE_FALLOCATE:
+ {
+ d = EF_SAFE_ALLOC(sizeof(struct t_data));
+
+ d->fd = fd;
+ d->command = command;
+ d->invoke = invoke_fallocate;
+ d->free = free_data;
+ d->level = 2;
+ d->c.fallocate.offset = get_int64((uchar*) buf);
+ d->c.fallocate.length = get_int64(((uchar*) buf) + sizeof(Sint64));
+ goto done;
+ }
+
}
/*
View
1 erts/emulator/drivers/common/erl_efile.h
@@ -154,3 +154,4 @@ int efile_symlink(Efile_error* errInfo, char* old, char* new);
int efile_may_openfile(Efile_error* errInfo, char *name);
int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length,
int advise);
+int efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length);
View
8 erts/emulator/drivers/common/ram_file_drv.c
@@ -48,6 +48,7 @@
#define RAM_FILE_SIZE 37 /* get file size */
#define RAM_FILE_ADVISE 38 /* predeclare the access
* pattern for file data */
+#define RAM_FILE_ALLOCATE 39 /* allocate space for a file */
/* possible new operations include:
DES_ENCRYPT
DES_DECRYPT
@@ -702,6 +703,13 @@ static void rfile_command(ErlDrvData e, char* buf, int count)
else
reply(f, 1, 0);
break;
+
+ case RAM_FILE_ALLOCATE:
+ if (f->flags == 0)
+ error_reply(f, EBADF);
+ else
+ reply(f, 1, 0);
+ break;
}
/*
* Ignore anything else -- let the caller hang.
View
10 erts/emulator/drivers/unix/unix_efile.c
@@ -1462,3 +1462,13 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
return check_error(0, errInfo);
#endif
}
+
+int
+efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length)
+{
+#ifdef HAVE_POSIX_FALLOCATE
+ return check_error(posix_fallocate(fd, offset, length), errInfo);
+#else
+ return check_error(0, errInfo);
+#endif
+}
View
8 erts/emulator/drivers/win32/win_efile.c
@@ -1446,3 +1446,11 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
errno = ERROR_SUCCESS;
return check_error(0, errInfo);
}
+
+int
+efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length)
+{
+ /* posix_fallocate is not available on Windows, do nothing */
+ errno = ERROR_SUCCESS;
+ return check_error(0, errInfo);
+}
View
7 erts/preloaded/src/prim_file.erl
@@ -27,6 +27,7 @@
%% Generic file contents operations
-export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1,
write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, copy/3]).
+-export([allocate/3]).
%% Specialized file operations
-export([open/1, open/3]).
@@ -98,6 +99,7 @@
-define(FILE_READ_LINE, 29).
-define(FILE_FDATASYNC, 30).
-define(FILE_ADVISE, 31).
+-define(FILE_ALLOCATE, 32).
%% Driver responses
-define(FILE_RESP_OK, 0).
@@ -261,6 +263,11 @@ advise(#file_descriptor{module = ?MODULE, data = {Port, _}},
end.
%% Returns {error, Reason} | ok.
+allocate(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offset, Length) ->
+ Cmd = <<?FILE_ALLOCATE, Offset:64/signed, Length:64/signed>>,
+ drv_command(Port, Cmd).
+
+%% Returns {error, Reason} | ok.
write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) ->
case drv_command(Port, [?FILE_WRITE,Bytes]) of
{ok, _Size} ->
View
15 lib/kernel/doc/src/file.xml
@@ -81,6 +81,21 @@ time() = {{Year, Month, Day}, {Hour, Minute, Second}}
</desc>
</func>
<func>
+ <name>allocate(IoDevice, Offset, Length) -> ok | {error, Reason}</name>
+ <fsummary>Allocate file space</fsummary>
+ <type>
+ <v>IoDevice = io_device()</v>
+ <v>Offset = int()</v>
+ <v>Length = int()</v>
+ <v>Reason = ext_posix()</v>
+ </type>
+ <desc>
+ <p><c>allocate/3</c> can be used to allocate space for a file.</p>
+ <p>This function only has effect on POSIX platforms that implement
+ the posix_fallocate system call.</p>
+ </desc>
+ </func>
+ <func>
<name>change_group(Filename, Gid) -> ok | {error, Reason}</name>
<fsummary>Change group of a file</fsummary>
<type>
View
11 lib/kernel/src/file.erl
@@ -36,7 +36,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,
@@ -378,6 +378,15 @@ advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
advise(_, _, _, _) ->
{error, badarg}.
+-spec allocate(File :: io_device(), Offset :: integer(), Length :: integer()) ->
+ 'ok' | {'error', posix()}.
+
+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(File :: io_device() | atom(), Size :: non_neg_integer()) ->
'eof' | {'ok', [char()] | binary()} | {'error', posix()}.
View
8 lib/kernel/src/file_io_server.erl
@@ -206,6 +206,14 @@ file_request({advise,Offset,Length,Advise},
Reply ->
{reply,Reply,State}
end;
+file_request({allocate, Offset, Length},
+ #state{handle = Handle} = State) ->
+ case ?PRIM_FILE:allocate(Handle, Offset, Length) of
+ {error, _} = Reply ->
+ {stop, normal, Reply, State};
+ Reply ->
+ {reply, Reply, State}
+ end;
file_request({pread,At,Sz},
#state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
case position(Handle, At, Buf) of
View
7 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}.
+
%%%-----------------------------------------------------------------
View
44 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
@@ -463,7 +465,7 @@ win_cur_dir_1(_Config) ->
files(suite) ->
[open,pos,file_info,consult,eval,script,truncate,
- sync,datasync,advise].
+ sync,datasync,advise,allocate].
open(suite) -> [open1,old_modes,new_modes,path_open,close,access,read_write,
pread_write,append,open_errors,exclusive].
@@ -1575,6 +1577,46 @@ 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]),
+ ?line ok = ?FILE_MODULE:allocate(Fd, 0, 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]),
+ ?line ok = ?FILE_MODULE:allocate(Fd2, 0, 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]),
+ ?line ok = ?FILE_MODULE:allocate(Fd3, 0, 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]),
+ ?line ok = ?FILE_MODULE:allocate(Fd4, 0, 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.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
View
43 lib/kernel/test/prim_file_SUITE.erl
@@ -50,6 +50,8 @@
-export([advise/1]).
+-export([allocate/1]).
+
-include("test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -382,7 +384,7 @@ win_cur_dir_1(_Config, Handle) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-files(suite) -> [open,pos,file_info,truncate,sync,datasync,advise].
+files(suite) -> [open,pos,file_info,truncate,sync,datasync,advise,allocate].
open(suite) -> [open1,modes,close,access,read_write,
pread_write,append,exclusive].
@@ -1188,6 +1190,45 @@ advise(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+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]),
+ ?line ok = ?PRIM_FILE:allocate(Fd, 0, 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]),
+ ?line ok = ?PRIM_FILE:allocate(Fd2, 0, 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]),
+ ?line ok = ?PRIM_FILE:allocate(Fd3, 0, 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]),
+ ?line ok = ?PRIM_FILE:allocate(Fd4, 0, 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.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

0 comments on commit ea3dfb9

Please sign in to comment.
Something went wrong with that request. Please try again.