diff options
author | Scott Lystig Fritchie <[email protected]> | 2011-11-17 00:47:23 -0600 |
---|---|---|
committer | Patrik Nyblom <[email protected]> | 2012-03-22 18:16:13 +0100 |
commit | ad6387b0242caa2b3c64d62a133752e10546211b (patch) | |
tree | 2125af8da5823487592cfeae6e21d03f8f71551b | |
parent | 2f532f889a6bd31f74122bd223277d7c609f7bdc (diff) | |
download | otp-ad6387b0242caa2b3c64d62a133752e10546211b.tar.gz otp-ad6387b0242caa2b3c64d62a133752e10546211b.tar.bz2 otp-ad6387b0242caa2b3c64d62a133752e10546211b.zip |
Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 4/4
Add probes to (mostly) the efile_drv.c driver and other
file I/O-related source files.
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 569 | ||||
-rw-r--r-- | erts/preloaded/ebin/prim_file.beam | bin | 39536 -> 46840 bytes | |||
-rw-r--r-- | erts/preloaded/src/prim_file.erl | 600 | ||||
-rw-r--r-- | lib/kernel/src/file.erl | 149 | ||||
-rw-r--r-- | lib/kernel/src/file_io_server.erl | 15 | ||||
-rw-r--r-- | lib/kernel/src/file_server.erl | 106 | ||||
-rw-r--r-- | lib/kernel/test/prim_file_SUITE.erl | 108 |
7 files changed, 1061 insertions, 486 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index a251b064da..b72f95792c 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -112,6 +112,8 @@ #include "erl_threads.h" #include "zlib.h" #include "gzio.h" +#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS +#include "dtrace-wrapper.h" #include <ctype.h> #include <sys/types.h> @@ -119,6 +121,40 @@ void erl_exit(int n, char *fmt, ...); static ErlDrvSysInfo sys_info; +/* For explanation of this var, see comment for same var in erl_async.c */ +static unsigned gcc_optimizer_hack = 0; + +#ifdef HAVE_DTRACE + +#define DTRACE_INVOKE_SETUP(op) \ + do { DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, op); } while (0) +#define DTRACE_INVOKE_SETUP_BY_NAME(op) \ + struct t_data *d = (struct t_data *) data ; \ + DTRACE_INVOKE_SETUP(op) +#define DTRACE_INVOKE_RETURN(op) \ + do { DTRACE3(efile_drv_int_return, d->sched_i1, d->sched_i2, \ + op); } while (0) ; gcc_optimizer_hack++ ; + +/* Assign human-friendlier id numbers to scheduler & I/O worker threads */ +int dt_driver_idnum = 0; +int dt_driver_io_worker_base = 5000; +erts_mtx_t dt_driver_mutex; +pthread_key_t dt_driver_key; + +typedef struct { + int thread_num; + Uint64 tag; +} dt_private; + +dt_private *get_dt_private(int); +#else /* HAVE_DTRACE */ +typedef struct { +} dt_private; + +#define DTRACE_INVOKE_SETUP(op) do {} while (0) +#define DTRACE_INVOKE_SETUP_BY_NAME(op) do {} while (0) +#define DTRACE_INVOKE_RETURN(op) do {} while (0) +#endif /* HAVE_DTRACE */ /* #define TRACE 1 */ #ifdef TRACE @@ -289,6 +325,10 @@ typedef struct { ErlDrvPDL q_mtx; /* Mutex for the driver queue, known by the emulator. Also used for mutual exclusion when accessing field(s) below. */ size_t write_buffered; +#ifdef HAVE_DTRACE + int idnum; /* Unique ID # for this driver thread/desc */ + char port_str[DTRACE_TERM_BUF_SIZE]; +#endif } file_descriptor; @@ -386,6 +426,13 @@ struct t_data void (*free)(void *); int again; int reply; +#ifdef HAVE_DTRACE + int sched_i1; + Uint64 sched_i2; + char sched_utag[128+1]; +#else + char sched_utag[1]; +#endif int result_ok; Efile_error errInfo; int flags; @@ -458,8 +505,6 @@ struct t_data char b[1]; }; - - #define EF_ALLOC(S) driver_alloc((S)) #define EF_REALLOC(P, S) driver_realloc((P), (S)) #define EF_SAFE_ALLOC(S) ef_safe_alloc((S)) @@ -488,7 +533,7 @@ static void *ef_safe_realloc(void *op, Uint s) * ErlIOVec manipulation functions. */ -/* char EV_CHAR(ErlIOVec *ev, int p, int q) */ +/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ #define EV_CHAR_P(ev, p, q) \ (((char *)(ev)->iov[(q)].iov_base) + (p)) @@ -683,6 +728,11 @@ file_init(void) : 0); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); +#ifdef HAVE_DTRACE + erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex"); + pthread_key_create(&dt_driver_key, NULL); +#endif /* HAVE_DTRACE */ + return 0; } @@ -722,6 +772,10 @@ file_start(ErlDrvPort port, char* command) desc->write_error = 0; MUTEX_INIT(desc->q_mtx, port); /* Refc is one, referenced by emulator now */ desc->write_buffered = 0; +#ifdef HAVE_DTRACE + dtrace_drvport_str(port, desc->port_str); + get_dt_private(0); /* throw away return value */ +#endif /* HAVE_DTRACE */ return (ErlDrvData) desc; } @@ -741,8 +795,10 @@ static void do_close(int flags, SWord fd) { static void invoke_close(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE_INVOKE_SETUP(FILE_CLOSE); d->again = 0; do_close(d->flags, d->fd); + DTRACE_INVOKE_RETURN(FILE_CLOSE); } /********************************************************************* @@ -972,49 +1028,63 @@ static void invoke_name(void *data, int (*f)(Efile_error *, char *)) static void invoke_mkdir(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_MKDIR); invoke_name(data, efile_mkdir); + DTRACE_INVOKE_RETURN(FILE_MKDIR); } static void invoke_rmdir(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_RMDIR); invoke_name(data, efile_rmdir); + DTRACE_INVOKE_RETURN(FILE_RMDIR); } static void invoke_delete_file(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_DELETE); invoke_name(data, efile_delete_file); + DTRACE_INVOKE_RETURN(FILE_DELETE); } static void invoke_chdir(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_CHDIR); invoke_name(data, efile_chdir); + DTRACE_INVOKE_RETURN(FILE_CHDIR); } static void invoke_fdatasync(void *data) { struct t_data *d = (struct t_data *) data; int fd = (int) d->fd; + DTRACE_INVOKE_SETUP(FILE_FDATASYNC); d->again = 0; d->result_ok = efile_fdatasync(&d->errInfo, fd); + DTRACE_INVOKE_RETURN(FILE_FDATASYNC); } static void invoke_fsync(void *data) { struct t_data *d = (struct t_data *) data; int fd = (int) d->fd; + DTRACE_INVOKE_SETUP(FILE_FSYNC); d->again = 0; d->result_ok = efile_fsync(&d->errInfo, fd); + DTRACE_INVOKE_RETURN(FILE_FSYNC); } static void invoke_truncate(void *data) { struct t_data *d = (struct t_data *) data; int fd = (int) d->fd; + DTRACE_INVOKE_SETUP(FILE_TRUNCATE); d->again = 0; d->result_ok = efile_truncate_file(&d->errInfo, &fd, d->flags); + DTRACE_INVOKE_RETURN(FILE_TRUNCATE); } static void invoke_read(void *data) @@ -1022,6 +1092,7 @@ static void invoke_read(void *data) struct t_data *d = (struct t_data *) data; int status, segment; size_t size, read_size; + DTRACE_INVOKE_SETUP(FILE_READ); segment = d->again && d->c.read.bin_size >= 2*FILE_SEGMENT_READ; if (segment) { @@ -1056,6 +1127,7 @@ static void invoke_read(void *data) } else { d->again = 0; } + DTRACE_INVOKE_RETURN(FILE_READ); } static void free_read(void *data) @@ -1072,6 +1144,7 @@ static void invoke_read_line(void *data) int status; size_t read_size; int local_loop = (d->again == 0); + DTRACE_INVOKE_SETUP(FILE_READ_LINE); do { size_t size = (d->c.read_line.binp)->orig_size - @@ -1163,6 +1236,7 @@ static void invoke_read_line(void *data) break; } } while (local_loop); + DTRACE_INVOKE_RETURN(FILE_READ_LINE); } static void free_read_line(void *data) @@ -1178,6 +1252,7 @@ static void invoke_read_file(void *data) struct t_data *d = (struct t_data *) data; size_t read_size; int chop; + DTRACE_INVOKE_SETUP(FILE_READ_FILE); if (! d->c.read_file.binp) { /* First invocation only */ int fd; @@ -1214,12 +1289,14 @@ static void invoke_read_file(void *data) &read_size); if (d->result_ok) { d->c.read_file.offset += read_size; - if (chop) return; /* again */ + if (chop) goto chop_done; /* again */ } close: efile_closefile((int) d->fd); done: d->again = 0; + chop_done: + DTRACE_INVOKE_RETURN(FILE_READ_FILE); } static void free_read_file(void *data) @@ -1239,6 +1316,7 @@ static void invoke_preadv(void *data) ErlIOVec *ev = &c->eiov; size_t bytes_read_so_far = 0; unsigned char *p = (unsigned char *)ev->iov[0].iov_base + 4+4+8*c->cnt; + DTRACE_INVOKE_SETUP(FILE_PREADV); while (c->cnt < c->n) { size_t read_size = ev->iov[1 + c->cnt].iov_len - c->size; @@ -1260,7 +1338,7 @@ static void invoke_preadv(void *data) bytes_read_so_far += bytes_read; if (chop && bytes_read == read_size) { c->size += bytes_read; - return; + goto done; } ASSERT(bytes_read <= read_size); ev->iov[1 + c->cnt].iov_len = bytes_read + c->size; @@ -1271,7 +1349,7 @@ static void invoke_preadv(void *data) if (d->again && bytes_read_so_far >= FILE_SEGMENT_READ && c->cnt < c->n) { - return; + goto done; } } else { /* In case of a read error, ev->size will not be correct, @@ -1282,6 +1360,8 @@ static void invoke_preadv(void *data) } } d->again = 0; + done: + DTRACE_INVOKE_RETURN(FILE_PREADV); } static void free_preadv(void *data) { @@ -1303,6 +1383,7 @@ static void invoke_ipread(void *data) size_t bytes_read = 0; char buf[2*sizeof(Uint32)]; Uint32 offset, size; + DTRACE_INVOKE_SETUP(FILE_IPREAD); /* Read indirection header */ if (! efile_pread(&d->errInfo, (int) d->fd, c->offsets[0], @@ -1341,14 +1422,17 @@ static void invoke_ipread(void *data) /* Read data block */ d->invoke = invoke_preadv; invoke_preadv(data); + DTRACE_INVOKE_RETURN(FILE_IPREAD); return; error: d->result_ok = 0; d->again = 0; + DTRACE_INVOKE_RETURN(FILE_IPREAD); return; done: d->result_ok = !0; d->again = 0; + DTRACE_INVOKE_RETURN(FILE_IPREAD); } /* invoke_writev and invoke_pwritev are the only thread functions that @@ -1371,6 +1455,7 @@ static void invoke_writev(void *data) { size_t size; size_t p; int segment; + DTRACE_INVOKE_SETUP(FILE_WRITE); segment = d->again && d->c.writev.size >= 2*FILE_SEGMENT_WRITE; if (segment) { @@ -1444,6 +1529,7 @@ static void invoke_writev(void *data) { TRACE_F(("w%lu", (unsigned long)size)); } + DTRACE_INVOKE_RETURN(FILE_WRITE); } static void free_writev(void *data) { @@ -1457,34 +1543,40 @@ static void free_writev(void *data) { static void invoke_pwd(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE_INVOKE_SETUP(FILE_PWD); d->again = 0; d->result_ok = efile_getdcwd(&d->errInfo,d->drive, d->b+1, RESBUFSIZE-1); + DTRACE_INVOKE_RETURN(FILE_PWD); } static void invoke_readlink(void *data) { struct t_data *d = (struct t_data *) data; char resbuf[RESBUFSIZE]; /* Result buffer. */ + DTRACE_INVOKE_SETUP(FILE_READLINK); d->again = 0; d->result_ok = efile_readlink(&d->errInfo, d->b, resbuf+1, RESBUFSIZE-1); if (d->result_ok != 0) FILENAME_COPY((char *) d->b + 1, resbuf+1); + DTRACE_INVOKE_RETURN(FILE_READLINK); } static void invoke_altname(void *data) { struct t_data *d = (struct t_data *) data; char resbuf[RESBUFSIZE]; /* Result buffer. */ + DTRACE_INVOKE_SETUP(FILE_ALTNAME); d->again = 0; d->result_ok = efile_altname(&d->errInfo, d->b, resbuf+1, RESBUFSIZE-1); if (d->result_ok != 0) FILENAME_COPY((char *) d->b + 1, resbuf+1); + DTRACE_INVOKE_RETURN(FILE_ALTNAME); } static void invoke_pwritev(void *data) { @@ -1497,6 +1589,7 @@ static void invoke_pwritev(void *data) { size_t p; int segment; size_t size, write_size; + DTRACE_INVOKE_SETUP(FILE_PWRITEV); segment = d->again && c->size >= 2*FILE_SEGMENT_WRITE; if (segment) { @@ -1576,6 +1669,7 @@ static void invoke_pwritev(void *data) { } done: EF_FREE(iov); /* Free our copy of the vector, nothing to restore */ + DTRACE_INVOKE_RETURN(FILE_PWRITEV); } static void free_pwritev(void *data) { @@ -1591,9 +1685,14 @@ static void invoke_flstat(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, + d->command == FILE_LSTAT ? FILE_LSTAT : FILE_FSTAT); d->again = 0; d->result_ok = efile_fileinfo(&d->errInfo, &d->info, d->b, d->command == FILE_LSTAT); + DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, + d->command == FILE_LSTAT ? FILE_LSTAT : FILE_FSTAT); + gcc_optimizer_hack++; } static void invoke_link(void *data) @@ -1601,10 +1700,12 @@ static void invoke_link(void *data) struct t_data *d = (struct t_data *) data; char *name = d->b; char *new_name; + DTRACE_INVOKE_SETUP(FILE_LINK); d->again = 0; new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE; d->result_ok = efile_link(&d->errInfo, name, new_name); + DTRACE_INVOKE_RETURN(FILE_LINK); } static void invoke_symlink(void *data) @@ -1612,10 +1713,12 @@ static void invoke_symlink(void *data) struct t_data *d = (struct t_data *) data; char *name = d->b; char *new_name; + DTRACE_INVOKE_SETUP(FILE_SYMLINK); d->again = 0; new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE; d->result_ok = efile_symlink(&d->errInfo, name, new_name); + DTRACE_INVOKE_RETURN(FILE_SYMLINK); } static void invoke_rename(void *data) @@ -1623,24 +1726,29 @@ static void invoke_rename(void *data) struct t_data *d = (struct t_data *) data; char *name = d->b; char *new_name; + DTRACE_INVOKE_SETUP(FILE_RENAME); d->again = 0; new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE; d->result_ok = efile_rename(&d->errInfo, name, new_name); + DTRACE_INVOKE_RETURN(FILE_RENAME); } static void invoke_write_info(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE_INVOKE_SETUP(FILE_WRITE_INFO); d->again = 0; d->result_ok = efile_write_info(&d->errInfo, &d->info, d->b); + DTRACE_INVOKE_RETURN(FILE_WRITE_INFO); } static void invoke_lseek(void *data) { struct t_data *d = (struct t_data *) data; int status; + DTRACE_INVOKE_SETUP(FILE_LSEEK); d->again = 0; if (d->flags & EFILE_COMPRESSED) { @@ -1665,6 +1773,7 @@ static void invoke_lseek(void *data) &d->c.lseek.location); } d->result_ok = status; + DTRACE_INVOKE_RETURN(FILE_LSEEK); } static void invoke_readdir(void *data) @@ -1675,6 +1784,7 @@ static void invoke_readdir(void *data) size_t n = 0, total = 0; struct t_readdir_buf *b = NULL; int res = 0; + DTRACE_INVOKE_SETUP(FILE_READDIR); d->again = 0; d->errInfo.posix_errno = 0; @@ -1710,13 +1820,14 @@ static void invoke_readdir(void *data) } while(res); d->result_ok = (d->errInfo.posix_errno == 0); + DTRACE_INVOKE_RETURN(FILE_READDIR); } static void invoke_open(void *data) { struct t_data *d = (struct t_data *) data; - int status = 1; /* Status of open call. */ + DTRACE_INVOKE_SETUP(FILE_OPEN); d->again = 0; if ((d->flags & EFILE_COMPRESSED) == 0) { @@ -1749,6 +1860,7 @@ static void invoke_open(void *data) } d->result_ok = status; + DTRACE_INVOKE_RETURN(FILE_OPEN); } static void invoke_fadvise(void *data) @@ -1758,9 +1870,11 @@ static void invoke_fadvise(void *data) off_t offset = (off_t) d->c.fadvise.offset; off_t length = (off_t) d->c.fadvise.length; int advise = (int) d->c.fadvise.advise; + DTRACE_INVOKE_SETUP(FILE_FADVISE); d->again = 0; d->result_ok = efile_fadvise(&d->errInfo, fd, offset, length, advise); + DTRACE_INVOKE_RETURN(FILE_FADVISE); } #ifdef HAVE_SENDFILE @@ -1841,6 +1955,7 @@ static void free_readdir(void *data) { struct t_data *d = (struct t_data *) data; struct t_readdir_buf *b1 = d->c.read_dir.first_buf; + while (b1) { struct t_readdir_buf *b2 = b1; b1 = b1->next; @@ -1909,12 +2024,13 @@ static void cq_execute(file_descriptor *desc) { DRIVER_ASYNC(d->level, desc, d->invoke, void_ptr=d, d->free); } -static int async_write(file_descriptor *desc, int *errp, - int reply, Uint32 reply_size) { +static struct t_data *async_write(file_descriptor *desc, int *errp, + int reply, Uint32 reply_size, + Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) { struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data) - 1))) { if (errp) *errp = ENOMEM; - return -1; + return NULL; } TRACE_F(("w%lu", (unsigned long)desc->write_buffered)); d->command = FILE_WRITE; @@ -1923,6 +2039,11 @@ static int async_write(file_descriptor *desc, int *errp, d->c.writev.port = desc->port; d->c.writev.q_mtx = desc->q_mtx; d->c.writev.size = desc->write_buffered; + if (dt_i1 != NULL) { + *dt_i1 = d->fd; + *dt_i2 = d->flags; + *dt_i3 = d->c.writev.size; + } d->reply = reply; d->c.writev.free_size = 0; d->c.writev.reply_size = reply_size; @@ -1931,18 +2052,41 @@ static int async_write(file_descriptor *desc, int *errp, d->level = 1; cq_enq(desc, d); desc->write_buffered = 0; - return 0; + return d; } -static int flush_write(file_descriptor *desc, int *errp) { - int result; +static int flush_write(file_descriptor *desc, int *errp, + dt_private *dt_priv, char *dt_utag) { + int result = 0; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; + struct t_data *d = NULL; + MUTEX_LOCK(desc->q_mtx); if (desc->write_buffered > 0) { - result = async_write(desc, errp, 0, 0); - } else { - result = 0; + if ((d = async_write(desc, errp, 0, 0, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { + result = -1; + } } MUTEX_UNLOCK(desc->q_mtx); +#ifdef HAVE_DTRACE + if (d != NULL) { + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, FILE_WRITE, + NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str); + } +#endif /* HAVE_DTRACE */ return result; } @@ -1955,9 +2099,10 @@ static int check_write_error(file_descriptor *desc, int *errp) { return 0; } -static int flush_write_check_error(file_descriptor *desc, int *errp) { +static int flush_write_check_error(file_descriptor *desc, int *errp, + dt_private *dt_priv, char *dt_utag) { int r; - if ( (r = flush_write(desc, errp)) != 0) { + if ( (r = flush_write(desc, errp, dt_priv, dt_utag)) != 0) { check_write_error(desc, NULL); return r; } else { @@ -1965,12 +2110,13 @@ static int flush_write_check_error(file_descriptor *desc, int *errp) { } } -static int async_lseek(file_descriptor *desc, int *errp, int reply, - Sint64 offset, int origin) { +static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply, + Sint64 offset, int origin, + Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) { struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data)))) { *errp = ENOMEM; - return -1; + return NULL; } d->flags = desc->flags; d->fd = desc->fd; @@ -1978,11 +2124,16 @@ static int async_lseek(file_descriptor *desc, int *errp, int reply, d->reply = reply; d->c.lseek.offset = offset; d->c.lseek.origin = origin; + if (dt_i1 != NULL) { + *dt_i1 = d->fd; + *dt_i2 = d->c.lseek.offset; + *dt_i3 = d->c.lseek.origin; + } d->invoke = invoke_lseek; d->free = free_data; d->level = 1; cq_enq(desc, d); - return 0; + return d; } static void flush_read(file_descriptor *desc) { @@ -1994,18 +2145,37 @@ static void flush_read(file_descriptor *desc) { } } -static int lseek_flush_read(file_descriptor *desc, int *errp) { +static int lseek_flush_read(file_descriptor *desc, int *errp, + dt_private *dt_priv, char *dt_utag) { int r = 0; size_t read_size = desc->read_size; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; + struct t_data *d; + + flush_read(desc); if (read_size != 0) { - flush_read(desc); - if ((r = async_lseek(desc, errp, 0, - -((ssize_t)read_size), EFILE_SEEK_CUR)) - < 0) { - return r; - } - } else { - flush_read(desc); + if ((d = async_lseek(desc, errp, 0, + -((ssize_t)read_size), EFILE_SEEK_CUR, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { + r = -1; + } else { +#ifdef HAVE_DTRACE + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, FILE_LSEEK, + NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str); +#endif /* HAVE_DTRACE */ + } } return r; } @@ -2022,11 +2192,23 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) struct t_data *d = (struct t_data *) data; char header[5]; /* result code + count */ char resbuf[RESBUFSIZE]; /* Result buffer. */ - +#ifdef HAVE_DTRACE + int sched_i1 = d->sched_i1, sched_i2 = d->sched_i2, command = d->command, + result_ok = d->result_ok, + posix_errno = d->result_ok ? 0 : d->errInfo.posix_errno; + DTRACE_CHARBUF(sched_utag, 128+1); + + sched_utag[0] = '\0'; + if (DTRACE_ENABLED(efile_drv_return)) { + strncpy(sched_utag, d->sched_utag, sizeof(sched_utag) - 1); + sched_utag[sizeof(sched_utag) - 1] = '\0'; + } +#endif /* HAVE_DTRACE */ TRACE_C('r'); if (try_again(desc, d)) { + /* DTRACE TODO: what kind of probe makes sense here? */ return; } @@ -2224,6 +2406,9 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) if (d->reply) { TRACE_C('K'); reply_ok(desc); +#ifdef HAVE_DTRACE + result_ok = 1; +#endif } free_data(data); break; @@ -2279,6 +2464,8 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) default: abort(); } + DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag, + command, result_ok, posix_errno); if (desc->write_buffered != 0 && desc->timer_state == timer_idle) { desc->timer_state = timer_write; driver_set_timer(desc->port, desc->write_delay); @@ -2301,7 +2488,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) char* name; /* Points to the filename in buf. */ int command; struct t_data *d = NULL; - + char *dt_utag = NULL, *dt_s1 = NULL, *dt_s2 = NULL; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0; +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(0); +#endif /* HAVE_DTRACE */ TRACE_C('o'); @@ -2316,6 +2507,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_mkdir; d->free = free_data; @@ -2327,6 +2520,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_rmdir; d->free = free_data; @@ -2338,6 +2533,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_delete_file; d->free = free_data; @@ -2354,7 +2551,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); + dt_s2 = d->b + namelen; + dt_utag = buf + namelen + strlen(dt_s2) + 1; d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2368,6 +2568,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_chdir; d->free = free_data; @@ -2379,6 +2581,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); d->drive = *(uchar*)buf; + dt_utag = buf + 1; d->command = command; d->invoke = invoke_pwd; d->free = free_data; @@ -2394,6 +2597,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->dir_handle = NULL; d->command = command; d->invoke = invoke_readdir; @@ -2418,6 +2623,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) dir_handle = NULL; resbuf[0] = FILE_RESP_LFNAME; + dt_s1 = name; + dt_utag = name + strlen(dt_s1) + 1; + /* Fill the buffer with multiple directory listings before sending it to the * receiving process. READDIR_CHUNKS is minimum number of files sent to the * receiver. @@ -2451,6 +2659,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) reply_error(desc, &errInfo); return; } +#ifdef HAVE_DTRACE + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, name, dt_s2, + dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str); +#endif TRACE_C('R'); driver_output2(desc->port, resbuf, 1, NULL, 0); return; @@ -2461,8 +2674,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); d->flags = get_int32((uchar*)buf); + dt_i1 = d->flags; name = buf+4; FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_open; d->free = free_data; @@ -2474,7 +2690,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); + dt_utag = name; d->fd = fd; + dt_i1 = fd; d->command = command; d->invoke = invoke_fdatasync; d->free = free_data; @@ -2486,7 +2704,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); + dt_utag = name; d->fd = fd; + dt_i1 = fd; d->command = command; d->invoke = invoke_fsync; d->free = free_data; @@ -2502,7 +2722,13 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_utag = name + strlen(d->b) + 1; d->fd = fd; + if (command == FILE_LSTAT) { + dt_s1 = d->b; + } else { + dt_i1 = fd; + } d->command = command; d->invoke = invoke_flstat; d->free = free_data; @@ -2514,8 +2740,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); + dt_utag = name; d->flags = desc->flags; d->fd = fd; + dt_i1 = fd; + dt_i2 = d->flags; d->command = command; d->invoke = invoke_truncate; d->free = free_data; @@ -2529,13 +2758,18 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE); d->info.mode = get_int32(buf + 0 * 4); + dt_i1 = d->info.mode; d->info.uid = get_int32(buf + 1 * 4); + dt_i2 = d->info.uid; d->info.gid = get_int32(buf + 2 * 4); + dt_i3 = d->info.gid; d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4)); d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4)); d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4)); FILENAME_COPY(d->b, buf + 9*4); + dt_s1 = d->b; + dt_utag = buf + 9 * 4 + strlen(d->b) + 1; d->command = command; d->invoke = invoke_write_info; d->free = free_data; @@ -2548,6 +2782,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_readlink; d->free = free_data; @@ -2559,6 +2795,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_altname; d->free = free_data; @@ -2578,7 +2816,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); + dt_s2 = d->b + namelen; + dt_utag = buf + namelen + strlen(dt_s2) + 1; d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2599,7 +2840,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); + dt_s2 = d->b + namelen; + dt_utag = buf + namelen + strlen(dt_s2) + 1; d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2614,13 +2858,18 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data)); d->fd = fd; + dt_i1 = d->fd; d->command = command; d->invoke = invoke_fadvise; d->free = free_data; d->level = 2; d->c.fadvise.offset = get_int64((uchar*) buf); + dt_i2 = d->c.fadvise.offset; d->c.fadvise.length = get_int64(((uchar*) buf) + sizeof(Sint64)); + dt_i3 = d->c.fadvise.length; d->c.fadvise.advise = get_int32(((uchar*) buf) + 2 * sizeof(Sint64)); + dt_i4 = d->c.fadvise.advise; + dt_utag = buf + 3 * sizeof(Sint64); goto done; } @@ -2634,6 +2883,22 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) done: if (d) { +#ifdef HAVE_DTRACE + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, dt_s1, dt_s2, + dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str); +#endif cq_enq(desc, d); } } @@ -2647,6 +2912,11 @@ file_flush(ErlDrvData e) { #ifdef DEBUG int r; #endif +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); +#else + dt_private *dt_priv = NULL; +#endif TRACE_C('f'); @@ -2657,7 +2927,8 @@ file_flush(ErlDrvData e) { #ifdef DEBUG r = #endif - flush_write(desc, NULL); + flush_write(desc, NULL, dt_priv, + (desc->d == NULL) ? NULL : desc->d->sched_utag); /* Only possible reason for bad return value is ENOMEM, and * there is nobody to tell... */ @@ -2699,6 +2970,11 @@ static void file_timeout(ErlDrvData e) { file_descriptor *desc = (file_descriptor *)e; enum e_timer timer_state = desc->timer_state; +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); +#else + dt_private *dt_priv = NULL; +#endif TRACE_C('t'); @@ -2716,7 +2992,8 @@ file_timeout(ErlDrvData e) { #ifdef DEBUG int r = #endif - flush_write(desc, NULL); + flush_write(desc, NULL, dt_priv, + (desc->d == NULL) ? NULL : desc->d->sched_utag); /* Only possible reason for bad return value is ENOMEM, and * there is nobody to tell... */ @@ -2737,7 +3014,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { char command; int p, q; int err; - + struct t_data *d = NULL; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0; + char *dt_utag = NULL, *dt_s1 = NULL; +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); +#else + dt_private *dt_priv = NULL; +#endif TRACE_C('v'); p = 0; q = 1; @@ -2756,25 +3040,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { switch (command) { case FILE_CLOSE: { + dt_utag = EV_CHAR_P(ev, p, q); flush_read(desc); - if (flush_write_check_error(desc, &err) < 0) { + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1) { - /* Wrong command length */ - reply_posix_error(desc, EINVAL); - goto done; - } if (desc->fd != FILE_FD_INVALID) { - struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data)))) { reply_posix_error(desc, ENOMEM); } else { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->invoke = invoke_close; d->free = free_data; d->level = 2; @@ -2790,8 +3071,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_READ: { Uint32 sizeH, sizeL; size_t size, alloc_size; - struct t_data *d; - if (flush_write_check_error(desc, &err) < 0) { + + if (!EV_GET_UINT32(ev, &sizeH, &p, &q) + || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { + /* Wrong buffer length to contain the read count */ + reply_posix_error(desc, EINVAL); + goto done; + } + dt_utag = EV_CHAR_P(ev, p, q); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } @@ -2799,19 +3087,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { if (desc->read_bufsize == 0 && desc->read_binp != NULL && desc->read_size > 0) { /* We have allocated a buffer for line mode but should not really have a read-ahead buffer... */ - if (lseek_flush_read(desc, &err) < 0) { + if (lseek_flush_read(desc, &err, dt_priv) < 0) { reply_posix_error(desc, err); goto done; } } #endif - if (ev->size != 1+8 - || !EV_GET_UINT32(ev, &sizeH, &p, &q) - || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { - /* Wrong buffer length to contain the read count */ - reply_posix_error(desc, EINVAL); - goto done; - } #if SIZEOF_SIZE_T == 4 if (sizeH != 0) { reply_posix_error(desc, EINVAL); @@ -2882,11 +3163,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.read.binp = desc->read_binp; d->c.read.bin_offset = desc->read_offset + desc->read_size; d->c.read.bin_size = desc->read_binp->orig_size - d->c.read.bin_offset; d->c.read.size = size; + dt_i3 = d->c.read.size; driver_binary_inc_refc(d->c.read.binp); d->invoke = invoke_read; d->free = free_read; @@ -2904,12 +3188,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { * allocated binary + dealing with offsets and lengts are done in file_async ready * for this OP. */ - struct t_data *d; - if (flush_write_check_error(desc, &err) < 0) { + dt_utag = EV_CHAR_P(ev, p, q); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1) { + if (ev->size != 1+strlen(dt_utag)+1) { /* Wrong command length */ reply_posix_error(desc, EINVAL); goto done; @@ -2961,13 +3245,17 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.read_line.binp = desc->read_binp; d->c.read_line.read_offset = desc->read_offset; d->c.read_line.read_size = desc->read_size; + dt_i3 = d->c.read_line.read_offset; #if !ALWAYS_READ_LINE_AHEAD d->c.read_line.read_ahead = (desc->read_bufsize > 0); #endif + dt_i4 = d->c.read_line.read_ahead; driver_binary_inc_refc(d->c.read.binp); d->invoke = invoke_read_line; d->free = free_read_line; @@ -2977,7 +3265,21 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_WRITE: { ErlDrvSizeT skip = 1; ErlDrvSizeT size = ev->size - skip; - if (lseek_flush_read(desc, &err) < 0) { + + dt_utag = EV_CHAR_P(ev, p, q); + skip += strlen(dt_utag) + 1; + size = ev->size - skip; + /* + * Interesting dependency on using port # for key to async + * I/O worker pool thread: lseek_flush_read() can enqueue a + * lseek() op. If that lseek() were scheduled on a different + * thread than the write that we'll enqueue later in this case, + * then Bad Things could happen. This DTrace work is probably + * well worthwhile to get a sense of how often there's head-of- + * line blocking/unfairness during busy file I/O because of the + * mapping of port #/key -> thread. + */ + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } @@ -3004,7 +3306,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { driver_set_timer(desc->port, desc->write_delay); } } else { - if (async_write(desc, &err, !0, size) != 0) { + if ((d = async_write(desc, &err, !0, size, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { MUTEX_UNLOCK(desc->q_mtx); reply_posix_error(desc, err); goto done; @@ -3017,19 +3320,25 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_PWRITEV: { Uint32 i, j, n; size_t total; - struct t_data *d; - if (lseek_flush_read(desc, &err) < 0) { - reply_Uint_posix_error(desc, 0, err); + char tmp; + int dt_utag_bytes = 1; + + dt_utag = EV_CHAR_P(ev, p, q); + while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') { + dt_utag_bytes++; + } + if (ev->size < 1+4+dt_utag_bytes + || !EV_GET_UINT32(ev, &n, &p, &q)) { + /* Buffer too short to contain even the number of pos/size specs */ + reply_Uint_posix_error(desc, 0, EINVAL); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_Uint_posix_error(desc, 0, err); goto done; } - if (ev->size < 1+4 - || !EV_GET_UINT32(ev, &n, &p, &q)) { - /* Buffer too short to contain even the number of pos/size specs */ - reply_Uint_posix_error(desc, 0, EINVAL); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + reply_Uint_posix_error(desc, 0, err); goto done; } if (n == 0) { @@ -3041,7 +3350,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } goto done; } - if (ev->size < 1+4+8*(2*n)) { + if (ev->size < 1+4+8*(2*n)+dt_utag_bytes) { /* Buffer too short to contain even the pos/size specs */ reply_Uint_posix_error(desc, 0, EINVAL); goto done; @@ -3055,7 +3364,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.pwritev.port = desc->port; d->c.pwritev.q_mtx = desc->q_mtx; d->c.pwritev.n = n; @@ -3093,13 +3404,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } d->c.pwritev.size = total; + dt_i3 = d->c.pwritev.size; d->c.pwritev.free_size = 0; if (j == 0) { /* Trivial case - nothing to write */ EF_FREE(d); reply_Uint(desc, 0); } else { - ErlDrvSizeT skip = 1 + 4 + 8*(2*n); + ErlDrvSizeT skip = 1 + 4 + 8 * (2*n) + dt_utag_bytes; if (skip + total != ev->size) { /* Actual amount of data does not match * total of all pos/size specs @@ -3123,24 +3435,30 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_PREADV: { register void * void_ptr; Uint32 i, n; - struct t_data *d; ErlIOVec *res_ev; - if (lseek_flush_read(desc, &err) < 0) { + char tmp; + int dt_utag_bytes = 1; + + dt_utag = EV_CHAR_P(ev, p, q); + while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') { + dt_utag_bytes++; + } + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size < 1+8 + if (ev->size < 1+8+dt_utag_bytes || !EV_GET_UINT32(ev, &n, &p, &q) || !EV_GET_UINT32(ev, &n, &p, &q)) { /* Buffer too short to contain even the number of pos/size specs */ reply_posix_error(desc, EINVAL); goto done; } - if (ev->size != 1+8+8*(2*n)) { + if (ev->size < 1+8+8*(2*n)+dt_utag_bytes) { /* Buffer wrong length to contain the pos/size specs */ reply_posix_error(desc, EINVAL); goto done; @@ -3159,7 +3477,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.preadv.n = n; d->c.preadv.cnt = 0; d->c.preadv.size = 0; @@ -3187,6 +3507,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else size = ((size_t)sizeH<<32) | sizeL; #endif + dt_i3 += size; if (! (res_ev->binv[i] = driver_alloc_binary(size))) { reply_posix_error(desc, ENOMEM); break; @@ -3233,31 +3554,33 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } goto done; /* case FILE_PREADV: */ case FILE_LSEEK: { - Sint64 offset; /* Offset for seek */ + Sint64 offset; /* Offset for seek */ Uint32 origin; /* Origin of seek. */ - if (lseek_flush_read(desc, &err) < 0) { - reply_posix_error(desc, err); + + if (ev->size < 1+8+4 + || !EV_GET_UINT64(ev, &offset, &p, &q) + || !EV_GET_UINT32(ev, &origin, &p, &q)) { + /* Wrong length of buffer to contain offset and origin */ + reply_posix_error(desc, EINVAL); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + dt_utag = EV_CHAR_P(ev, p, q); + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1+8+4 - || !EV_GET_UINT64(ev, &offset, &p, &q) - || !EV_GET_UINT32(ev, &origin, &p, &q)) { - /* Wrong length of buffer to contain offset and origin */ - reply_posix_error(desc, EINVAL); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + reply_posix_error(desc, err); goto done; } - if (async_lseek(desc, &err, !0, offset, origin) < 0) { + if ((d = async_lseek(desc, &err, !0, offset, origin, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { reply_posix_error(desc, err); goto done; } } goto done; case FILE_READ_FILE: { - struct t_data *d; char *filename; if (ev->size < 1+1) { /* Buffer contains empty name */ @@ -3279,6 +3602,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; /* Copy name */ FILENAME_COPY(d->b, filename); + dt_s1 = d->b; + dt_utag = filename + strlen(d->b) + 1; d->c.read_file.binp = NULL; d->invoke = invoke_read_file; d->free = free_read_file; @@ -3298,7 +3623,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { char mode; Sint64 hdr_offset; Uint32 max_size; - struct t_data *d; ErlIOVec *res_ev; int vsize; if (! EV_GET_CHAR(ev, &mode, &p, &q)) { @@ -3310,14 +3634,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } - if (lseek_flush_read(desc, &err) < 0) { - reply_posix_error(desc, err); - goto done; - } - if (flush_write_check_error(desc, &err) < 0) { - reply_posix_error(desc, err); - goto done; - } if (ev->size < 1+1+8+4 || !EV_GET_UINT64(ev, &hdr_offset, &p, &q) || !EV_GET_UINT32(ev, &max_size, &p, &q)) { @@ -3326,6 +3642,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } + dt_utag = EV_CHAR_P(ev, p, q); + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { + reply_posix_error(desc, err); + goto done; + } + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + reply_posix_error(desc, err); + goto done; + } /* Create the thread data structure with the contained ErlIOVec * and corresponding binaries for the response */ @@ -3339,9 +3664,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.preadv.offsets[0] = hdr_offset; + dt_i3 = d->c.preadv.offsets[0]; d->c.preadv.size = max_size; + dt_i4 = d->c.preadv.size; res_ev = &d->c.preadv.eiov; /* XXX possible alignment problems here for weird machines */ res_ev->iov = void_ptr = d + 1; @@ -3356,16 +3685,19 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_SETOPT: { char opt; + if (ev->size < 1+1 || !EV_GET_CHAR(ev, &opt, &p, &q)) { /* Buffer too short to contain even the option type */ reply_posix_error(desc, EINVAL); goto done; } + dt_i1 = opt; + dt_utag = EV_CHAR_P(ev, p, q); switch (opt) { case FILE_OPT_DELAYED_WRITE: { Uint32 sizeH, sizeL, delayH, delayL; - if (ev->size != 1+1+4*sizeof(Uint32) + if (ev->size != 1+1+4*sizeof(Uint32)+strlen(dt_utag)+1 || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q) || !EV_GET_UINT32(ev, &delayH, &p, &q) @@ -3392,12 +3724,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->write_delay = ((unsigned long)delayH << 32) | delayL; #endif + dt_i2 = desc->write_delay; TRACE_C('K'); reply_ok(desc); } goto done; case FILE_OPT_READ_AHEAD: { Uint32 sizeH, sizeL; - if (ev->size != 1+1+2*sizeof(Uint32) + if (ev->size != 1+1+2*sizeof(Uint32)+strlen(dt_utag)+1 || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { /* Buffer has wrong length to contain the option values */ @@ -3413,6 +3746,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->read_bufsize = ((size_t)sizeH << 32) | sizeL; #endif + dt_i2 = desc->read_bufsize; TRACE_C('K'); reply_ok(desc); } goto done; @@ -3499,11 +3833,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } /* switch(command) */ - if (lseek_flush_read(desc, &err) < 0) { + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } else { @@ -3521,5 +3855,46 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } done: + if (d != NULL) { +#ifdef HAVE_DTRACE + /* + * If d == NULL, then either: + * 1). There was an error of some sort, or + * 2). The command given to us is actually implemented + * by file_output() instead. + * + * Case #1 is probably a TODO item, perhaps? + * Case #2 we definitely don't want to activate a probe. + */ + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, dt_s1, NULL, dt_i1, dt_i2, dt_i3, dt_i4, + desc->port_str); +#endif + } cq_execute(desc); } + +#ifdef HAVE_DTRACE +dt_private * +get_dt_private(int base) +{ + dt_private *dt_priv = (dt_private *) pthread_getspecific(dt_driver_key); + + if (dt_priv == NULL) { + dt_priv = EF_SAFE_ALLOC(sizeof(dt_private)); + erts_mtx_lock(&dt_driver_mutex); + dt_priv->thread_num = (base + dt_driver_idnum++); + erts_mtx_unlock(&dt_driver_mutex); + dt_priv->tag = 0; + pthread_setspecific(dt_driver_key, dt_priv); + } + return dt_priv; +} +#endif /* HAVE_DTRACE */ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 87e80aae9b..9d6c47ffc1 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 36cbe329e8..5c9cad3a2c 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -25,39 +25,59 @@ %%% Interface towards a single file's contents. Uses ?FD_DRV. %% 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, sendfile/10]). + +-export([ + open/2, open/3, + close/1, close/2, + datasync/1, datasync/2, + sync/1, sync/2, + advise/4, advise/5, + position/2, position/3, + truncate/1, truncate/2, + write/2, write/3, + pwrite/2, pwrite/3, pwrite/4, + read/2, read/3, + read_line/1, read_line/2, + pread/2, pread/3, pread/4, + copy/3, copy/4, + sendfile/10 + ]). %% Specialized file operations --export([open/1, open/3]). --export([read_file/1, read_file/2, write_file/2]). --export([ipread_s32bu_p32bu/3]). +-export([open/1]). +-export([read_file/1, read_file/2, read_file/3, write_file/2, write_file/3]). +-export([ipread_s32bu_p32bu/3, ipread_s32bu_p32bu/4]). %%% Interface towards file system and metadata. Uses ?DRV. %% Takes an optional port (opens a ?DRV port per default) as first argument. --export([get_cwd/0, get_cwd/1, get_cwd/2, - set_cwd/1, set_cwd/2, - delete/1, delete/2, - rename/2, rename/3, - make_dir/1, make_dir/2, - del_dir/1, del_dir/2, - read_file_info/1, read_file_info/2, read_file_info/3, - altname/1, altname/2, - write_file_info/2, write_file_info/3, write_file_info/4, - make_link/2, make_link/3, - make_symlink/2, make_symlink/3, - read_link/1, read_link/2, - read_link_info/1, read_link_info/2, read_link_info/3, - list_dir/1, list_dir/2]). + +-export([ + get_cwd/0, get_cwd/1, get_cwd/3, + set_cwd/1, set_cwd/3, + delete/1, delete/2, delete/3, + rename/2, rename/3, rename/4, + make_dir/1, make_dir/3, + del_dir/1, del_dir/3, + read_file_info/1, read_file_info/2, read_file_info/3, read_file_info/4, + altname/1, altname/3, + write_file_info/2, write_file_info/4, write_file_info/5, + make_link/2, make_link/3, make_link/4, + make_symlink/2, make_symlink/3, make_symlink/4, + read_link/1, read_link/3, + read_link_info/1, read_link_info/2, read_link_info/3, read_link_info/4, + list_dir/1, list_dir/3 + ]). %% How to start and stop the ?DRV port. -export([start/0, stop/1]). %% Debug exports --export([open_int/4, open_mode/1, open_mode/4]). +-export([open_int/4, open_int/5, open_mode/1, open_mode/4]). + +%% For DTrace/Systemtap tracing +-export([get_dtrace_utag/0]). %%%----------------------------------------------------------------- %%% Includes and defines @@ -155,30 +175,21 @@ %%% Supposed to be called by applications through module file. -%% Opens a file using the driver port Port. Returns {error, Reason} -%% | {ok, FileDescriptor} -open(Port, File, ModeList) when is_port(Port), - (is_list(File) orelse is_binary(File)), - is_list(ModeList) -> - case open_mode(ModeList) of - {Mode, _Portopts, _Setopts} -> - open_int(Port, File, Mode, []); - Reason -> - {error, Reason} - end; -open(_,_,_) -> - {error, badarg}. - %% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}. -open(File, ModeList) when (is_list(File) orelse is_binary(File)), - is_list(ModeList) -> +open(File, ModeList) -> + open(File, ModeList, get_dtrace_utag()). + +open(File, ModeList, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + is_list(ModeList), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> case open_mode(ModeList) of {Mode, Portopts, Setopts} -> - open_int({?FD_DRV, Portopts},File, Mode, Setopts); + open_int({?FD_DRV, Portopts}, File, Mode, Setopts, DTraceUtag); Reason -> {error, Reason} end; -open(_, _) -> +open(_, _, _) -> {error, badarg}. %% Opens a port that can be used for open/3 or read_file/2. @@ -193,29 +204,34 @@ open(Portopts) when is_list(Portopts) -> open(_) -> {error, badarg}. -open_int({Driver, Portopts}, File, Mode, Setopts) -> +open_int(Arg, File, Mode, Setopts) -> + open_int(Arg, File, Mode, Setopts, get_dtrace_utag()). + +open_int({Driver, Portopts}, File, Mode, Setopts, DTraceUtag) -> + %% TODO: add DTraceUtag to drv_open()? case drv_open(Driver, Portopts) of {ok, Port} -> - open_int(Port, File, Mode, Setopts); + open_int(Port, File, Mode, Setopts, DTraceUtag); {error, _} = Error -> Error end; -open_int(Port, File, Mode, Setopts) -> +open_int(Port, File, Mode, Setopts, DTraceUtag) -> M = Mode band ?EFILE_MODE_MASK, - case drv_command(Port, [<<?FILE_OPEN, M:32>>, pathname(File)]) of + case drv_command(Port, [<<?FILE_OPEN, M:32>>, + pathname(File), enc_utag(DTraceUtag)]) of {ok, Number} -> - open_int_setopts(Port, Number, Setopts); + open_int_setopts(Port, Number, Setopts, DTraceUtag); Error -> drv_close(Port), Error end. -open_int_setopts(Port, Number, []) -> +open_int_setopts(Port, Number, [], _DTraceUtag) -> {ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}}; -open_int_setopts(Port, Number, [Cmd | Tail]) -> - case drv_command(Port, Cmd) of +open_int_setopts(Port, Number, [Cmd | Tail], DTraceUtag) -> + case drv_command(Port, [Cmd, enc_utag(DTraceUtag)]) of ok -> - open_int_setopts(Port, Number, Tail); + open_int_setopts(Port, Number, Tail, DTraceUtag); Error -> drv_close(Port), Error @@ -225,50 +241,64 @@ open_int_setopts(Port, Number, [Cmd | Tail]) -> %% Returns ok. -close(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - case drv_command(Port, <<?FILE_CLOSE>>) of +close(Arg) -> + close(Arg, get_dtrace_utag()). + +close(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + case drv_command(Port, [<<?FILE_CLOSE>>, enc_utag(DTraceUtag)]) of ok -> drv_close(Port); Error -> Error end; %% Closes a port opened with open/1. -close(Port) when is_port(Port) -> +close(Port, _DTraceUtag) when is_port(Port) -> drv_close(Port). --define(ADVISE(Offs, Len, Adv), +-define(ADVISE(Offs, Len, Adv, BUtag), <<?FILE_ADVISE, Offs:64/signed, Len:64/signed, - Adv:32/signed>>). + Adv:32/signed, BUtag/binary>>). %% Returns {error, Reason} | ok. +advise(FD, Offset, Length, Advise) -> + advise(FD, Offset, Length, Advise, get_dtrace_utag()). + advise(#file_descriptor{module = ?MODULE, data = {Port, _}}, - Offset, Length, Advise) -> + Offset, Length, Advise, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + BUtag = term_to_binary(enc_utag(DTraceUtag)), case Advise of normal -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL, BUtag), drv_command(Port, Cmd); random -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM, BUtag), drv_command(Port, Cmd); sequential -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL, BUtag), drv_command(Port, Cmd); will_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED, BUtag), drv_command(Port, Cmd); dont_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED, BUtag), drv_command(Port, Cmd); no_reuse -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE, BUtag), drv_command(Port, Cmd); _ -> {error, einval} end. %% Returns {error, Reason} | ok. -write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> - case drv_command(Port, [?FILE_WRITE,Bytes]) of +write(Desc, Bytes) -> + write(Desc, Bytes, get_dtrace_utag()). + +write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + %% This is rare case where DTraceUtag is not at end of command list. + case drv_command(Port, [?FILE_WRITE,enc_utag(DTraceUtag),Bytes]) of {ok, _Size} -> ok; Error -> @@ -278,39 +308,40 @@ write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> %% Returns ok | {error, {WrittenCount, Reason}} pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pwrite_int(Port, L, 0, [], []). + pwrite_int(Port, L, 0, [], [], get_dtrace_utag()). -pwrite_int(_, [], 0, [], []) -> +pwrite_int(_, [], 0, [], [], _DTraceUtag) -> ok; -pwrite_int(Port, [], N, Spec, Data) -> - Header = list_to_binary([<<?FILE_PWRITEV, N:32>> | reverse(Spec)]), +pwrite_int(Port, [], N, Spec, Data, DTraceUtag) -> + Header = list_to_binary([<<?FILE_PWRITEV>>, enc_utag(DTraceUtag), + <<N:32>>, reverse(Spec)]), case drv_command_raw(Port, [Header | reverse(Data)]) of {ok, _Size} -> ok; Error -> Error end; -pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data) +pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data, DTraceUtag) when is_integer(Offs) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bytes); + pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag); true -> {error, einval} end; -pwrite_int(_, [_|_], _N, _Spec, _Data) -> +pwrite_int(_, [_|_], _N, _Spec, _Data, _DTraceUtag) -> {error, badarg}. -pwrite_int(Port, T, N, Spec, Data, Offs, Bin) +pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) when is_binary(Bin) -> Size = byte_size(Bin), pwrite_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec], - [Bin | Data]); -pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> + [Bin | Data], DTraceUtag); +pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag) -> try list_to_binary(Bytes) of Bin -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bin) + pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) catch error:Reason -> {error, Reason} @@ -319,11 +350,28 @@ pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> %% Returns {error, Reason} | ok. -pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) + when is_list(L), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pwrite_int(Port, L, 0, [], [], DTraceUtag); + +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) when is_integer(Offs) -> + pwrite_int2(Port, Offs, Bytes, get_dtrace_utag()); +pwrite(#file_descriptor{module = ?MODULE}, _, _) -> + {error, badarg}. + +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes, DTraceUtag) + when is_integer(Offs), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pwrite_int2(Port, Offs, Bytes, DTraceUtag); +pwrite(#file_descriptor{module = ?MODULE}, _, _, _DTraceUtag) -> + {error, badarg}. + +pwrite_int2(Port, Offs, Bytes, DTraceUtag) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of + case pwrite_int(Port, [], 0, [], [], Offs, Bytes, DTraceUtag) of {error, {_, Reason}} -> {error, Reason}; Result -> @@ -331,22 +379,30 @@ pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) end; true -> {error, einval} - end; -pwrite(#file_descriptor{module = ?MODULE}, _, _) -> - {error, badarg}. - + end. %% Returns {error, Reason} | ok. -datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, [?FILE_FDATASYNC]). +datasync(FD) -> + datasync(FD, get_dtrace_utag()). + +datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [?FILE_FDATASYNC, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | ok. -sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, [?FILE_FSYNC]). +sync(FD) -> + sync(FD, get_dtrace_utag()). + +sync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [?FILE_FSYNC, enc_utag(DTraceUtag)]). %% Returns {ok, Data} | eof | {error, Reason}. -read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - case drv_command(Port, <<?FILE_READ_LINE>>) of +read_line(FD) -> + read_line(FD, get_dtrace_utag()). + +read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) -> + case drv_command(Port, [<<?FILE_READ_LINE>>, enc_utag(DTraceUtag)]) of {ok, {0, _Data}} -> eof; {ok, {_Size, Data}} -> @@ -366,11 +422,17 @@ read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> end. %% Returns {ok, Data} | eof | {error, Reason}. -read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) - when is_integer(Size), 0 =< Size -> +read(FD, Size) -> + read(FD, Size, get_dtrace_utag()). + +read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag) + when is_integer(Size), + 0 =< Size, + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if Size < ?LARGEFILESIZE -> - case drv_command(Port, <<?FILE_READ, Size:64>>) of + case drv_command(Port, [<<?FILE_READ, Size:64>>, + enc_utag(DTraceUtag)]) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -379,7 +441,8 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) %% Garbage collecting here might help if %% the current processes have some old binaries left. erlang:garbage_collect(), - case drv_command(Port, <<?FILE_READ, Size:64>>) of + case drv_command(Port, [<<?FILE_READ, Size:64>>, + enc_utag(DTraceUtag)]) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -397,35 +460,43 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) %% Returns {ok, [Data|eof, ...]} | {error, Reason} pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pread_int(Port, L, 0, []). + pread_int(Port, L, 0, [], get_dtrace_utag()). -pread_int(_, [], 0, []) -> +pread_int(_, [], 0, [], _DTraceUtag) -> {ok, []}; -pread_int(Port, [], N, Spec) -> - drv_command(Port, [<<?FILE_PREADV, 0:32, N:32>> | reverse(Spec)]); -pread_int(Port, [{Offs, Size} | T], N, Spec) +pread_int(Port, [], N, Spec, DTraceUtag) -> + drv_command(Port, [<<?FILE_PREADV>>, enc_utag(DTraceUtag), + <<0:32, N:32>>, reverse(Spec)]); +pread_int(Port, [{Offs, Size} | T], N, Spec, DTraceUtag) when is_integer(Offs), is_integer(Size), 0 =< Size -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> - pread_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec]); + pread_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec], + DTraceUtag); true -> {error, einval} end; -pread_int(_, [_|_], _N, _Spec) -> +pread_int(_, [_|_], _N, _Spec, _DTraceUtag) -> {error, badarg}. - - %% Returns {ok, Data} | eof | {error, Reason}. -pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) + when is_list(L), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pread_int(Port, L, 0, [], get_dtrace_utag()); +pread(FD, Offs, Size) when is_integer(Offs), is_integer(Size), 0 =< Size -> + pread(FD, Offs, Size, get_dtrace_utag()). + +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> case drv_command(Port, - <<?FILE_PREADV, 0:32, 1:32, - Offs:64/signed, Size:64>>) of + [<<?FILE_PREADV>>, enc_utag(DTraceUtag), + <<0:32, 1:32, Offs:64/signed, Size:64>>]) of {ok, [eof]} -> eof; {ok, [Data]} -> @@ -436,17 +507,22 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) true -> {error, einval} end; -pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) -> +pread(_, _, _, _) -> {error, badarg}. %% Returns {ok, Position} | {error, Reason}. -position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> +position(FD, At) -> + position(FD, At, get_dtrace_utag()). + +position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> case lseek_position(At) of {Offs, Whence} when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - drv_command(Port, <<?FILE_LSEEK, Offs:64/signed, Whence:32>>); + drv_command(Port, [<<?FILE_LSEEK, Offs:64/signed, Whence:32>>, + enc_utag(DTraceUtag)]); {_, _} -> {error, einval}; Reason -> @@ -454,63 +530,89 @@ position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> end. %% Returns {error, Reaseon} | ok. -truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, <<?FILE_TRUNCATE>>). +truncate(FD) -> + truncate(FD, get_dtrace_utag()). + +truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [<<?FILE_TRUNCATE>>, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | {ok, BytesCopied} +copy(Source, Dest, Length) -> + copy(Source, Dest, Length, get_dtrace_utag()). + copy(#file_descriptor{module = ?MODULE} = Source, #file_descriptor{module = ?MODULE} = Dest, - Length) + Length, DTraceUtag) when is_integer(Length), Length >= 0; - is_atom(Length) -> + is_atom(Length), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> %% XXX Should be moved down to the driver for optimization. - file:copy_opened(Source, Dest, Length). + file:copy_opened(Source, Dest, Length, DTraceUtag). + +ipread_s32bu_p32bu(FD, Offs, Arg) -> + ipread_s32bu_p32bu(FD, Offs, Arg, get_dtrace_utag()). ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}} = Handle, Offs, - Infinity) when is_atom(Infinity) -> + Infinity, + DTraceUtag) + when is_atom(Infinity), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1); ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, - MaxSize) - when is_integer(Offs), is_integer(MaxSize) -> + MaxSize, + DTraceUtag) + when is_integer(Offs), + is_integer(MaxSize), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, 0 =< MaxSize, MaxSize < (1 bsl 31) -> - drv_command(Port, <<?FILE_IPREAD, ?IPREAD_S32BU_P32BU, - Offs:64, MaxSize:32>>); + drv_command(Port, [<<?FILE_IPREAD, ?IPREAD_S32BU_P32BU, + Offs:64, MaxSize:32>>, enc_utag(DTraceUtag)]); true -> {error, einval} end; ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}}, _Offs, - _MaxSize) -> + _MaxSize, + _DTraceUtag) -> {error, badarg}. %% Returns {ok, Contents} | {error, Reason} read_file(File) when (is_list(File) orelse is_binary(File)) -> + read_file(File, get_dtrace_utag()); +read_file(_) -> + {error, badarg}. + +read_file(File, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag))-> case drv_open(?FD_DRV, [binary]) of {ok, Port} -> - Result = read_file(Port, File), + Result = read_file(Port, File, DTraceUtag), close(Port), Result; {error, _} = Error -> Error end; -read_file(_) -> +read_file(_, _) -> {error, badarg}. %% Takes a Port opened with open/1. -read_file(Port, File) when is_port(Port), +read_file(Port, File, DTraceUtag) when is_port(Port), (is_list(File) orelse is_binary(File)) -> - Cmd = [?FILE_READ_FILE | pathname(File)], + Cmd = [?FILE_READ_FILE | + list_to_binary([pathname(File), enc_utag(DTraceUtag)])], case drv_command(Port, Cmd) of {error, enomem} -> %% It could possibly help to do a @@ -522,22 +624,30 @@ read_file(Port, File) when is_port(Port), Result -> Result end; -read_file(_,_) -> +read_file(_,_,_) -> {error, badarg}. %% Returns {error, Reason} | ok. -write_file(File, Bin) when (is_list(File) orelse is_binary(File)) -> +write_file(File, Bin) -> + write_file(File, Bin, get_dtrace_utag()). + +write_file(File, Bin, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + OldUtag = put(dtrace_utag, DTraceUtag), % TODO: API? case open(File, [binary, write]) of {ok, Handle} -> Result = write(Handle, Bin), close(Handle), + put(dtrace_utag, OldUtag), Result; Error -> + put(dtrace_utag, OldUtag), Error end; -write_file(_, _) -> +write_file(_, _, _) -> {error, badarg}. @@ -601,54 +711,56 @@ stop(Port) when is_port(Port) -> -%% get_cwd/{0,1,2} +%% get_cwd/{0,1,3} get_cwd() -> - get_cwd_int(0). + get_cwd_int(0, get_dtrace_utag()). get_cwd(Port) when is_port(Port) -> - get_cwd_int(Port, 0); + get_cwd_int(Port, 0, get_dtrace_utag()); get_cwd([]) -> - get_cwd_int(0); + get_cwd_int(0, get_dtrace_utag()); get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z -> - get_cwd_int(Letter - $a + 1); + get_cwd_int(Letter - $a + 1, get_dtrace_utag()); get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z -> - get_cwd_int(Letter - $A + 1); + get_cwd_int(Letter - $A + 1, get_dtrace_utag()); get_cwd([_|_]) -> {error, einval}; get_cwd(_) -> {error, badarg}. -get_cwd(Port, []) when is_port(Port) -> - get_cwd_int(Port, 0); -get_cwd(Port, [Letter, $: | _]) +get_cwd(Port, [], DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, 0, DTraceUtag); +get_cwd(Port, no_drive, DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, 0, DTraceUtag); +get_cwd(Port, [Letter, $: | _], DTraceUtag) when is_port(Port), $a =< Letter, Letter =< $z -> - get_cwd_int(Port, Letter - $a + 1); -get_cwd(Port, [Letter, $: | _]) + get_cwd_int(Port, Letter - $a + 1, DTraceUtag); +get_cwd(Port, [Letter, $: | _], DTraceUtag) when is_port(Port), $A =< Letter, Letter =< $Z -> - get_cwd_int(Port, Letter - $A + 1); -get_cwd(Port, [_|_]) when is_port(Port) -> + get_cwd_int(Port, Letter - $A + 1, DTraceUtag); +get_cwd(Port, [_|_], _DTraceUtag) when is_port(Port) -> {error, einval}; -get_cwd(_, _) -> +get_cwd(_, _, _DTraceUtag) -> {error, badarg}. -get_cwd_int(Drive) -> - get_cwd_int({?DRV, [binary]}, Drive). +get_cwd_int(Drive, DTraceUtag) -> + get_cwd_int({?DRV, [binary]}, Drive, DTraceUtag). -get_cwd_int(Port, Drive) -> - drv_command(Port, <<?FILE_PWD, Drive>>). +get_cwd_int(Port, Drive, DTraceUtag) -> + drv_command(Port, list_to_binary([?FILE_PWD, Drive, enc_utag(DTraceUtag)])). -%% set_cwd/{1,2} +%% set_cwd/{1,3} set_cwd(Dir) -> - set_cwd_int({?DRV, [binary]}, Dir). + set_cwd_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -set_cwd(Port, Dir) when is_port(Port) -> - set_cwd_int(Port, Dir). +set_cwd(Port, Dir, DTraceUtag) when is_port(Port) -> + set_cwd_int(Port, Dir, DTraceUtag). -set_cwd_int(Port, Dir0) -> +set_cwd_int(Port, Dir0, DTraceUtag) -> Dir = (catch case os:type() of @@ -658,7 +770,7 @@ set_cwd_int(Port, Dir0) -> %% must call get_cwd from here and use %% absname/2, since %% absname/1 uses file:get_cwd ... - case get_cwd_int(Port, 0) of + case get_cwd_int(Port, 0, "") of {ok, AbsPath} -> filename:absname(Dir0, AbsPath); _Badcwd -> @@ -669,78 +781,86 @@ set_cwd_int(Port, Dir0) -> end), %% Dir is now either a string or an EXIT tuple. %% An EXIT tuple will fail in the following catch. - drv_command(Port, [?FILE_CHDIR, pathname(Dir)]). + drv_command(Port, [?FILE_CHDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% delete/{1,2} +%% delete/{1,2,3} delete(File) -> - delete_int({?DRV, [binary]}, File). + delete_int({?DRV, [binary]}, File, get_dtrace_utag()). delete(Port, File) when is_port(Port) -> - delete_int(Port, File). + delete_int(Port, File, get_dtrace_utag()). + +delete(Port, File, DTraceUtag) when is_port(Port) -> + delete_int(Port, File, DTraceUtag). -delete_int(Port, File) -> - drv_command(Port, [?FILE_DELETE, pathname(File)]). +delete_int(Port, File, DTraceUtag) -> + drv_command(Port, [?FILE_DELETE, pathname(File), enc_utag(DTraceUtag)]). -%% rename/{2,3} +%% rename/{2,3,4} rename(From, To) -> - rename_int({?DRV, [binary]}, From, To). + rename_int({?DRV, [binary]}, From, To, get_dtrace_utag()). rename(Port, From, To) when is_port(Port) -> - rename_int(Port, From, To). + rename_int(Port, From, To, get_dtrace_utag()). + +rename(Port, From, To, DTraceUtag) when is_port(Port) -> + rename_int(Port, From, To, DTraceUtag). -rename_int(Port, From, To) -> - drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]). +rename_int(Port, From, To, DTraceUtag) -> + drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To), + enc_utag(DTraceUtag)]). -%% make_dir/{1,2} +%% make_dir/{1,3} make_dir(Dir) -> - make_dir_int({?DRV, [binary]}, Dir). + make_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -make_dir(Port, Dir) when is_port(Port) -> - make_dir_int(Port, Dir). +make_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + make_dir_int(Port, Dir, DTraceUtag). -make_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_MKDIR, pathname(Dir)]). +make_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_MKDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% del_dir/{1,2} +%% del_dir/{1,3} del_dir(Dir) -> - del_dir_int({?DRV, [binary]}, Dir). + del_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -del_dir(Port, Dir) when is_port(Port) -> - del_dir_int(Port, Dir). +del_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + del_dir_int(Port, Dir, DTraceUtag). -del_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_RMDIR, pathname(Dir)]). +del_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_RMDIR, pathname(Dir), enc_utag(DTraceUtag)]). - - -%% read_file_info/{1,2,3} +%% read_file_info/{1,2,3,4} read_file_info(File) -> - read_file_info_int({?DRV, [binary]}, File, local). + read_file_info_int({?DRV, [binary]}, File, local, get_dtrace_utag()). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File, local); + read_file_info_int(Port, File, local, get_dtrace_utag()); read_file_info(File, Opts) -> - read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)). + read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local), get_dtrace_utag()). -read_file_info(Port, File, Opts) when is_port(Port) -> - read_file_info_int(Port, File, plgv(time, Opts, local)). +read_file_info(Port, File, Opts) when is_port(Port), is_list(Opts) -> + read_file_info_int(Port, File, plgv(time, Opts, local), get_dtrace_utag()). -read_file_info_int(Port, File, TimeType) -> +read_file_info(Port, File, Opts, DTraceUtag) when is_port(Port) -> + read_file_info_int(Port, File, plgv(time, Opts, local), DTraceUtag). + +read_file_info_int(Port, File, TimeType, DTraceUtag) -> try - case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of + case drv_command(Port, [?FILE_FSTAT, pathname(File), enc_utag(DTraceUtag)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -752,30 +872,33 @@ read_file_info_int(Port, File, TimeType) -> error:_ -> {error, badarg} end. - -%% altname/{1,2} +%% altname/{1,3} altname(File) -> - altname_int({?DRV, [binary]}, File). + altname_int({?DRV, [binary]}, File, get_dtrace_utag()). -altname(Port, File) when is_port(Port) -> - altname_int(Port, File). +altname(Port, File, DTraceUtag) when is_port(Port) -> + altname_int(Port, File, DTraceUtag). -altname_int(Port, File) -> - drv_command(Port, [?FILE_ALTNAME, pathname(File)]). +altname_int(Port, File, DTraceUtag) -> + drv_command(Port, [?FILE_ALTNAME, pathname(File), enc_utag(DTraceUtag)]). -%% write_file_info/{2,3,4} + +%% write_file_info/{2,3,4,5} write_file_info(File, Info) -> - write_file_info_int({?DRV, [binary]}, File, Info, local). + write_file_info_int({?DRV, [binary]}, File, Info, local, get_dtrace_utag()). write_file_info(Port, File, Info) when is_port(Port) -> - write_file_info_int(Port, File, Info, local); + write_file_info_int(Port, File, Info, local, get_dtrace_utag()); write_file_info(File, Info, Opts) -> - write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)). + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local), get_dtrace_utag()). write_file_info(Port, File, Info, Opts) when is_port(Port) -> - write_file_info_int(Port, File, Info, plgv(time, Opts, local)). + write_file_info_int(Port, File, Info, plgv(time, Opts, local), get_dtrace_utag()). + +write_file_info(Port, File, Info, Opts, DTraceUtag) when is_port(Port) -> + write_file_info_int(Port, File, Info, plgv(time, Opts, local), DTraceUtag). write_file_info_int(Port, File, #file_info{mode=Mode, @@ -784,7 +907,8 @@ write_file_info_int(Port, File, atime=Atime0, mtime=Mtime0, ctime=Ctime0}, - TimeType) -> + TimeType, + DTraceUtag) -> % Atime and/or Mtime might be undefined % - use localtime() for atime, if atime is undefined @@ -803,12 +927,13 @@ write_file_info_int(Port, File, int_to_int64bytes(to_seconds(Atime, TimeType)), int_to_int64bytes(to_seconds(Mtime, TimeType)), int_to_int64bytes(to_seconds(Ctime, TimeType)), - pathname(File)]) + pathname(File), + enc_utag(DTraceUtag) + ]) catch error:_ -> {error, badarg} end. - file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; file_info_validate_atime(undefined, local) -> erlang:localtime(); file_info_validate_atime(undefined, universal) -> erlang:universaltime(); @@ -820,63 +945,72 @@ file_info_validate_mtime(Mtime, _) -> Mtime. file_info_validate_ctime(undefined, Mtime) -> Mtime; file_info_validate_ctime(Ctime, _) -> Ctime. -%% make_link/{2,3} +%% make_link/{2,3,4} make_link(Old, New) -> - make_link_int({?DRV, [binary]}, Old, New). + make_link_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). make_link(Port, Old, New) when is_port(Port) -> - make_link_int(Port, Old, New). + make_link_int(Port, Old, New, get_dtrace_utag()). -make_link_int(Port, Old, New) -> - drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]). +make_link(Port, Old, New, DTraceUtag) when is_port(Port) -> + make_link_int(Port, Old, New, DTraceUtag). +make_link_int(Port, Old, New, DTraceUtag) -> + drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New), + enc_utag(DTraceUtag)]). -%% make_symlink/{2,3} + +%% make_symlink/{2,3,4} make_symlink(Old, New) -> - make_symlink_int({?DRV, [binary]}, Old, New). + make_symlink_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). make_symlink(Port, Old, New) when is_port(Port) -> - make_symlink_int(Port, Old, New). + make_symlink_int(Port, Old, New, get_dtrace_utag()). + +make_symlink(Port, Old, New, DTraceUtag) when is_port(Port) -> + make_symlink_int(Port, Old, New, DTraceUtag). -make_symlink_int(Port, Old, New) -> - drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]). +make_symlink_int(Port, Old, New, DTraceUtag) -> + drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New), + enc_utag(DTraceUtag)]). -%% read_link/{2,3} +%% read_link/{1,3} read_link(Link) -> - read_link_int({?DRV, [binary]}, Link). + read_link_int({?DRV, [binary]}, Link, get_dtrace_utag()). -read_link(Port, Link) when is_port(Port) -> - read_link_int(Port, Link). +read_link(Port, Link, DTraceUtag) when is_port(Port) -> + read_link_int(Port, Link, DTraceUtag). -read_link_int(Port, Link) -> - drv_command(Port, [?FILE_READLINK, pathname(Link)]). +read_link_int(Port, Link, DTraceUtag) -> + drv_command(Port, [?FILE_READLINK, pathname(Link), enc_utag(DTraceUtag)]). -%% read_link_info/{2,3} +%% read_link_info/{1,2,3,4} read_link_info(Link) -> - read_link_info_int({?DRV, [binary]}, Link, local). + read_link_info_int({?DRV, [binary]}, Link, local, get_dtrace_utag()). read_link_info(Port, Link) when is_port(Port) -> - read_link_info_int(Port, Link, local); - + read_link_info_int(Port, Link, local, get_dtrace_utag()); read_link_info(Link, Opts) -> - read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)). + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local), get_dtrace_utag()). read_link_info(Port, Link, Opts) when is_port(Port) -> - read_link_info_int(Port, Link, plgv(time, Opts, local)). + read_link_info_int(Port, Link, plgv(time, Opts, local), get_dtrace_utag()). +read_link_info(Port, Link, Opts, DTraceUtag) when is_port(Port) -> + read_link_info_int(Port, Link, plgv(time, Opts, local), DTraceUtag). -read_link_info_int(Port, Link, TimeType) -> +read_link_info_int(Port, Link, TimeType, DTraceUtag) -> try - case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of + case drv_command(Port, [?FILE_LSTAT, pathname(Link), enc_utag(DTraceUtag)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -888,16 +1022,16 @@ read_link_info_int(Port, Link, TimeType) -> error:_ -> {error, badarg} end. -%% list_dir/{1,2} +%% list_dir/{1,3} list_dir(Dir) -> - list_dir_int({?DRV, [binary]}, Dir). + list_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -list_dir(Port, Dir) when is_port(Port) -> - list_dir_int(Port, Dir). +list_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + list_dir_int(Port, Dir, DTraceUtag). -list_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_READDIR, pathname(Dir)], []). +list_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_READDIR, pathname(Dir), enc_utag(DTraceUtag)], []). @@ -1335,7 +1469,6 @@ reverse(L, T) -> lists:reverse(L, T). pathname(File) -> (catch prim_file:internal_name2native(File)). - %% proplist:get_value/3 plgv(K, [{K, V}|_], _) -> V; plgv(K, [_|KVs], D) -> plgv(K, KVs, D); @@ -1359,3 +1492,20 @@ to_seconds({_,_} = Datetime, universal) -> erlang:universaltime_to_posixtime(Datetime); to_seconds({_,_} = Datetime, local) -> erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). + +%% TODO: Duplicate code! +get_dtrace_utag() -> + case get(dtrace_utag) of + X when is_list(X) -> + X; + _ -> + "" + end. + +%% TODO: Measure if it's worth checking (re:run()?) for NUL byte first? +enc_utag([0|Cs]) -> + enc_utag(Cs); +enc_utag([C|Cs]) -> + [C|enc_utag(Cs)]; +enc_utag([]) -> + [0]. diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 4028dd4f0b..a2e0d261ee 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -39,7 +39,7 @@ -export([ipread_s32bu_p32bu/3]). %% Generic file contents. -export([open/2, close/1, advise/4, - read/2, write/2, + read/2, write/2, pread/2, pread/3, pwrite/2, pwrite/3, read_line/1, position/2, truncate/1, datasync/1, sync/1, @@ -62,7 +62,7 @@ %% Internal export to prim_file and ram_file until they implement %% an efficient copy themselves. --export([copy_opened/3]). +-export([copy_opened/4]). -export([ipread_s32bu_p32bu_int/3]). @@ -166,7 +166,7 @@ pid2name(Pid) when is_pid(Pid) -> Reason :: posix(). get_cwd() -> - call(get_cwd, []). + call(get_cwd, [no_drive, get_dtrace_utag()]). -spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when Drive :: string(), @@ -174,21 +174,21 @@ get_cwd() -> Reason :: posix() | badarg. get_cwd(Drive) -> - check_and_call(get_cwd, [file_name(Drive)]). + check_and_call(get_cwd, [file_name(Drive), get_dtrace_utag()]). -spec set_cwd(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. set_cwd(Dirname) -> - check_and_call(set_cwd, [file_name(Dirname)]). + check_and_call(set_cwd, [file_name(Dirname), get_dtrace_utag()]). -spec delete(Filename) -> ok | {error, Reason} when Filename :: name(), Reason :: posix() | badarg. delete(Name) -> - check_and_call(delete, [file_name(Name)]). + check_and_call(delete, [file_name(Name), get_dtrace_utag()]). -spec rename(Source, Destination) -> ok | {error, Reason} when Source :: name(), @@ -196,21 +196,21 @@ delete(Name) -> Reason :: posix() | badarg. rename(From, To) -> - check_and_call(rename, [file_name(From), file_name(To)]). + check_and_call(rename, [file_name(From), file_name(To), get_dtrace_utag()]). -spec make_dir(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. make_dir(Name) -> - check_and_call(make_dir, [file_name(Name)]). + check_and_call(make_dir, [file_name(Name), get_dtrace_utag()]). -spec del_dir(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. del_dir(Name) -> - check_and_call(del_dir, [file_name(Name)]). + check_and_call(del_dir, [file_name(Name), get_dtrace_utag()]). -spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), @@ -218,7 +218,7 @@ del_dir(Name) -> Reason :: posix() | badarg. read_file_info(Name) -> - check_and_call(read_file_info, [file_name(Name)]). + check_and_call(read_file_info, [file_name(Name), get_dtrace_utag()]). -spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), @@ -232,7 +232,7 @@ read_file_info(Name, Opts) when is_list(Opts) -> -spec altname(Name :: name()) -> any(). altname(Name) -> - check_and_call(altname, [file_name(Name)]). + check_and_call(altname, [file_name(Name), get_dtrace_utag()]). -spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when Name :: name(), @@ -240,7 +240,7 @@ altname(Name) -> Reason :: posix() | badarg. read_link_info(Name) -> - check_and_call(read_link_info, [file_name(Name)]). + check_and_call(read_link_info, [file_name(Name), get_dtrace_utag()]). -spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when Name :: name(), @@ -258,7 +258,7 @@ read_link_info(Name, Opts) when is_list(Opts) -> Reason :: posix() | badarg. read_link(Name) -> - check_and_call(read_link, [file_name(Name)]). + check_and_call(read_link, [file_name(Name), get_dtrace_utag()]). -spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when Filename :: name(), @@ -266,7 +266,7 @@ read_link(Name) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}) -> - check_and_call(write_file_info, [file_name(Name), Info]). + check_and_call(write_file_info, [file_name(Name), Info, get_dtrace_utag()]). -spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when Filename :: name(), @@ -283,7 +283,7 @@ write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> Reason :: posix() | badarg. list_dir(Name) -> - check_and_call(list_dir, [file_name(Name)]). + check_and_call(list_dir, [file_name(Name), get_dtrace_utag()]). -spec read_file(Filename) -> {ok, Binary} | {error, Reason} when Filename :: name(), @@ -291,7 +291,7 @@ list_dir(Name) -> Reason :: posix() | badarg | terminated | system_limit. read_file(Name) -> - check_and_call(read_file, [file_name(Name)]). + check_and_call(read_file, [file_name(Name), get_dtrace_utag()]). -spec make_link(Existing, New) -> ok | {error, Reason} when Existing :: name(), @@ -299,7 +299,7 @@ read_file(Name) -> Reason :: posix() | badarg. make_link(Old, New) -> - check_and_call(make_link, [file_name(Old), file_name(New)]). + check_and_call(make_link, [file_name(Old), file_name(New), get_dtrace_utag()]). -spec make_symlink(Existing, New) -> ok | {error, Reason} when Existing :: name(), @@ -307,7 +307,7 @@ make_link(Old, New) -> Reason :: posix() | badarg. make_symlink(Old, New) -> - check_and_call(make_symlink, [file_name(Old), file_name(New)]). + check_and_call(make_symlink, [file_name(Old), file_name(New), get_dtrace_utag()]). -spec write_file(Filename, Bytes) -> ok | {error, Reason} when Filename :: name(), @@ -315,7 +315,7 @@ make_symlink(Old, New) -> Reason :: posix() | badarg | terminated | system_limit. write_file(Name, Bin) -> - check_and_call(write_file, [file_name(Name), make_binary(Bin)]). + check_and_call(write_file, [file_name(Name), make_binary(Bin), get_dtrace_utag()]). %% This whole operation should be moved to the file_server and prim_file %% when it is time to change file server protocol again. @@ -367,7 +367,7 @@ raw_write_file_info(Name, #file_info{} = Info) -> case check_args(Args) of ok -> [FileName] = Args, - ?PRIM_FILE:write_file_info(FileName, Info); + ?PRIM_FILE:write_file_info(FileName, Info, get_dtrace_utag()); Error -> Error end. @@ -400,7 +400,7 @@ open(Item, ModeList) when is_list(ModeList) -> [FileName | _] = Args, %% We rely on the returned Handle (in {ok, Handle}) %% being a pid() or a #file_descriptor{} - ?PRIM_FILE:open(FileName, ModeList); + ?PRIM_FILE:open(FileName, ModeList, get_dtrace_utag()); Error -> Error end @@ -421,7 +421,7 @@ open(Item, ModeList) when is_list(ModeList) -> case check_args(Args) of ok -> [FileName | _] = Args, - call(open, [FileName, ModeList]); + call(open, [FileName, ModeList, get_dtrace_utag()]); Error -> Error end @@ -466,7 +466,10 @@ close(_) -> advise(File, Offset, Length, Advise) when is_pid(File) -> R = file_request(File, {advise, Offset, Length, Advise}), wait_file_reply(File, R); +advise(#file_descriptor{module = prim_file = Module} = Handle, Offset, Length, Advise) -> + Module:advise(Handle, Offset, Length, Advise, get_dtrace_utag()); advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:advise(Handle, Offset, Length, Advise); advise(_, _, _, _) -> {error, badarg}. @@ -477,17 +480,25 @@ advise(_, _, _, _) -> Data :: string() | binary(), Reason :: posix() | badarg | terminated. -read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> +read(File, Sz) -> + read(File, Sz, get_dtrace_utag()). + +read(File, Sz, _DTraceUtag) + when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> case io:request(File, {get_chars, '', Sz}) of Data when is_list(Data); is_binary(Data) -> {ok, Data}; Other -> Other end; -read(#file_descriptor{module = Module} = Handle, Sz) +read(#file_descriptor{module = prim_file = Module} = Handle, Sz, DTraceUtag) + when is_integer(Sz), Sz >= 0 -> + Module:read(Handle, Sz, DTraceUtag); +read(#file_descriptor{module = Module} = Handle, Sz, _DTraceUtag) when is_integer(Sz), Sz >= 0 -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:read(Handle, Sz); -read(_, _) -> +read(_, _, _) -> {error, badarg}. -spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when @@ -502,7 +513,10 @@ read_line(File) when (is_pid(File) orelse is_atom(File)) -> Other -> Other end; +read_line(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:read_line(Handle, get_dtrace_utag()); read_line(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:read_line(Handle); read_line(_) -> {error, badarg}. @@ -516,7 +530,10 @@ read_line(_) -> pread(File, L) when is_pid(File), is_list(L) -> pread_int(File, L, []); +pread(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) -> + Module:pread(Handle, L, get_dtrace_utag()); pread(#file_descriptor{module = Module} = Handle, L) when is_list(L) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pread(Handle, L); pread(_, _) -> {error, badarg}. @@ -548,6 +565,7 @@ pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 -> wait_file_reply(File, R); pread(#file_descriptor{module = Module} = Handle, Offs, Sz) when is_integer(Sz), Sz >= 0 -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pread(Handle, Offs, Sz); pread(_, _, _) -> {error, badarg}. @@ -557,16 +575,22 @@ pread(_, _, _) -> Bytes :: iodata(), Reason :: posix() | badarg | terminated. -write(File, Bytes) when (is_pid(File) orelse is_atom(File)) -> +write(File, Bytes) -> + write(File, Bytes, get_dtrace_utag()). + +write(File, Bytes, _DTraceUtag) when (is_pid(File) orelse is_atom(File)) -> case make_binary(Bytes) of Bin when is_binary(Bin) -> io:request(File, {put_chars,Bin}); Error -> Error end; -write(#file_descriptor{module = Module} = Handle, Bytes) -> +write(#file_descriptor{module = prim_file = Module} = Handle, Bytes, DTraceUtag) -> + Module:write(Handle, Bytes, DTraceUtag); +write(#file_descriptor{module = Module} = Handle, Bytes, _DTraceUtag) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:write(Handle, Bytes); -write(_, _) -> +write(_, _, _) -> {error, badarg}. -spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when @@ -577,7 +601,10 @@ write(_, _) -> pwrite(File, L) when is_pid(File), is_list(L) -> pwrite_int(File, L, 0); +pwrite(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) -> + Module:pwrite(Handle, L, get_dtrace_utag()); pwrite(#file_descriptor{module = Module} = Handle, L) when is_list(L) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pwrite(Handle, L); pwrite(_, _) -> {error, badarg}. @@ -604,6 +631,7 @@ pwrite(File, At, Bytes) when is_pid(File) -> R = file_request(File, {pwrite, At, Bytes}), wait_file_reply(File, R); pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pwrite(Handle, Offs, Bytes); pwrite(_, _, _) -> {error, badarg}. @@ -615,7 +643,10 @@ pwrite(_, _, _) -> datasync(File) when is_pid(File) -> R = file_request(File, datasync), wait_file_reply(File, R); +datasync(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:datasync(Handle, get_dtrace_utag()); datasync(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:datasync(Handle); datasync(_) -> {error, badarg}. @@ -627,7 +658,10 @@ datasync(_) -> sync(File) when is_pid(File) -> R = file_request(File, sync), wait_file_reply(File, R); +sync(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:sync(Handle, get_dtrace_utag()); sync(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:sync(Handle); sync(_) -> {error, badarg}. @@ -641,7 +675,10 @@ sync(_) -> position(File, At) when is_pid(File) -> R = file_request(File, {position,At}), wait_file_reply(File, R); +position(#file_descriptor{module = prim_file = Module} = Handle, At) -> + Module:position(Handle, At, get_dtrace_utag()); position(#file_descriptor{module = Module} = Handle, At) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:position(Handle, At); position(_, _) -> {error, badarg}. @@ -653,7 +690,10 @@ position(_, _) -> truncate(File) when is_pid(File) -> R = file_request(File, truncate), wait_file_reply(File, R); +truncate(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:truncate(Handle, get_dtrace_utag()); truncate(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:truncate(Handle); truncate(_) -> {error, badarg}. @@ -694,7 +734,7 @@ copy_int(Source, Dest, Length) when is_pid(Source), is_pid(Dest); is_pid(Source), is_record(Dest, file_descriptor); is_record(Source, file_descriptor), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0); + copy_opened_int(Source, Dest, Length, get_dtrace_utag()); %% Copy between open raw files, both handled by the same module copy_int(#file_descriptor{module = Module} = Source, #file_descriptor{module = Module} = Dest, @@ -703,14 +743,14 @@ copy_int(#file_descriptor{module = Module} = Source, %% Copy between open raw files of different modules copy_int(#file_descriptor{} = Source, #file_descriptor{} = Dest, Length) -> - copy_opened_int(Source, Dest, Length, 0); + copy_opened_int(Source, Dest, Length, get_dtrace_utag()); %% Copy between filenames, let the server do the copy copy_int({SourceName, SourceOpts}, {DestName, DestOpts}, Length) when is_list(SourceOpts), is_list(DestOpts) -> check_and_call(copy, [file_name(SourceName), SourceOpts, file_name(DestName), DestOpts, - Length]); + Length, get_dtrace_utag()]); %% Filename -> open file; must open Source and do client copy copy_int({SourceName, SourceOpts}, Dest, Length) when is_list(SourceOpts), is_pid(Dest); @@ -721,7 +761,8 @@ copy_int({SourceName, SourceOpts}, Dest, Length) Source -> case open(Source, [read | SourceOpts]) of {ok, Handle} -> - Result = copy_opened_int(Handle, Dest, Length, 0), + Result = copy_opened_int(Handle, Dest, Length, + get_dtrace_utag()), close(Handle), Result; {error, _} = Error -> @@ -738,7 +779,8 @@ copy_int(Source, {DestName, DestOpts}, Length) Dest -> case open(Dest, [write | DestOpts]) of {ok, Handle} -> - Result = copy_opened_int(Source, Handle, Length, 0), + Result = copy_opened_int(Source, Handle, Length, + get_dtrace_utag()), close(Handle), Result; {error, _} = Error -> @@ -773,45 +815,46 @@ copy_int(Source, Dest, Length) -> -copy_opened(Source, Dest, Length) +copy_opened(Source, Dest, Length, DTraceUtag) when is_integer(Length), Length >= 0; is_atom(Length) -> - copy_opened_int(Source, Dest, Length); -copy_opened(_, _, _) -> + copy_opened_int(Source, Dest, Length, DTraceUtag); +copy_opened(_, _, _, _) -> {error, badarg}. %% Here we know that Length is either an atom or an integer >= 0 %% (by the way, atoms > integers) -copy_opened_int(Source, Dest, Length) +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_pid(Source), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(Source, Dest, Length) + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_pid(Source), is_record(Dest, file_descriptor) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(Source, Dest, Length) + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_record(Source, file_descriptor), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(Source, Dest, Length) + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_record(Source, file_descriptor), is_record(Dest, file_descriptor) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(_, _, _) -> + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(_, _, _, _) -> {error, badarg}. %% Here we know that Source and Dest are handles to open files, Length is %% as above, and Copied is an integer >= 0 %% Copy loop in client process -copy_opened_int(_, _, Length, Copied) when Length =< 0 -> % atom() > integer() +copy_opened_int(_, _, Length, Copied, _DTraceUtag) + when Length =< 0 -> % atom() > integer() {ok, Copied}; -copy_opened_int(Source, Dest, Length, Copied) -> +copy_opened_int(Source, Dest, Length, Copied, DTraceUtag) -> N = if Length > 65536 -> 65536; true -> Length end, % atom() > integer() ! - case read(Source, N) of + case read(Source, N, DTraceUtag) of {ok, Data} -> M = if is_binary(Data) -> byte_size(Data); is_list(Data) -> length(Data) end, - case write(Dest, Data) of + case write(Dest, Data, DTraceUtag) of ok -> if M < N -> %% Got less than asked for - must be end of file @@ -821,7 +864,8 @@ copy_opened_int(Source, Dest, Length, Copied) -> NewLength = if is_atom(Length) -> Length; true -> Length-M end, - copy_opened_int(Source, Dest, NewLength, Copied+M) + copy_opened_int(Source, Dest, NewLength, Copied+M, + DTraceUtag) end; {error, _} = Error -> Error @@ -841,6 +885,8 @@ copy_opened_int(Source, Dest, Length, Copied) -> ipread_s32bu_p32bu(File, Pos, MaxSize) when is_pid(File) -> ipread_s32bu_p32bu_int(File, Pos, MaxSize); +ipread_s32bu_p32bu(#file_descriptor{module = prim_file = Module} = Handle, Pos, MaxSize) -> + Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize, get_dtrace_utag()); ipread_s32bu_p32bu(#file_descriptor{module = Module} = Handle, Pos, MaxSize) -> Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize); ipread_s32bu_p32bu(_, _, _) -> @@ -1456,3 +1502,6 @@ wait_file_reply(From, Ref) -> %% receive {'EXIT', From, _} -> ok after 0 -> ok end, {error, terminated} end. + +get_dtrace_utag() -> + prim_file:get_dtrace_utag(). diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 14da9c1a55..cc0343031b 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -21,7 +21,7 @@ %% A simple file server for io to one file instance per server instance. -export([format_error/1]). --export([start/3, start_link/3]). +-export([start/4, start_link/4]). -export([count_and_find/3]). @@ -43,18 +43,18 @@ format_error({_Line, Mod, Reason}) -> format_error(ErrorId) -> erl_posix_msg:message(ErrorId). -start(Owner, FileName, ModeList) +start(Owner, FileName, ModeList, DTraceUtag) when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) -> - do_start(spawn, Owner, FileName, ModeList). + do_start(spawn, Owner, FileName, ModeList, DTraceUtag). -start_link(Owner, FileName, ModeList) +start_link(Owner, FileName, ModeList, DTraceUtag) when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) -> - do_start(spawn_link, Owner, FileName, ModeList). + do_start(spawn_link, Owner, FileName, ModeList, DTraceUtag). %%%----------------------------------------------------------------- %%% Server starter, dispatcher and helpers -do_start(Spawn, Owner, FileName, ModeList) -> +do_start(Spawn, Owner, FileName, ModeList, DTraceUtag) -> Self = self(), Ref = make_ref(), Pid = @@ -63,11 +63,12 @@ do_start(Spawn, Owner, FileName, ModeList) -> %% process_flag(trap_exit, true), case parse_options(ModeList) of {ReadMode, UnicodeMode, Opts} -> - case ?PRIM_FILE:open(FileName, Opts) of + case ?PRIM_FILE:open(FileName, Opts, DTraceUtag) of {error, Reason} = Error -> Self ! {Ref, Error}, exit(Reason); {ok, Handle} -> + put(dtrace_utag, DTraceUtag), % TODO: API? %% XXX must I handle R6 nodes here? M = erlang:monitor(process, Owner), Self ! {Ref, ok}, diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index fc6cd823c9..c917819508 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -76,6 +76,7 @@ stop() -> init([]) -> process_flag(trap_exit, true), + put(dtrace_utag, atom_to_list(?FILE_SERVER)), case ?PRIM_FILE:start() of {ok, Handle} -> ets:new(?FILE_IO_SERVER_TABLE, [named_table]), @@ -99,9 +100,9 @@ init([]) -> {'reply', 'eof' | 'ok' | {'error', term()} | {'ok', term()}, state()} | {'stop', 'normal', 'stopped', state()}. -handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle) +handle_call({open, Name, ModeList, DTraceUtag}, {Pid, _Tag} = _From, Handle) when is_list(ModeList) -> - Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList), + Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList, DTraceUtag), case Child of {ok, P} when is_pid(P) -> ets:insert(?FILE_IO_SERVER_TABLE, {P, Name}); @@ -110,87 +111,86 @@ handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle) end, {reply, Child, Handle}; -handle_call({open, _Name, _Mode}, _From, Handle) -> +handle_call({open, _Name, _Mode, _DTraceUtag}, _From, Handle) -> {reply, {error, einval}, Handle}; -handle_call({read_file, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file(Name), Handle}; +handle_call({read_file, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file(Name, DTraceUtag), Handle}; -handle_call({write_file, Name, Bin}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file(Name, Bin), Handle}; +handle_call({write_file, Name, Bin, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file(Name, Bin, DTraceUtag), Handle}; -handle_call({set_cwd, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:set_cwd(Handle, Name), Handle}; +handle_call({set_cwd, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:set_cwd(Handle, Name, DTraceUtag), Handle}; -handle_call({delete, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:delete(Handle, Name), Handle}; +handle_call({delete, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:delete(Handle, Name, DTraceUtag), Handle}; -handle_call({rename, Fr, To}, _From, Handle) -> - {reply, ?PRIM_FILE:rename(Handle, Fr, To), Handle}; +handle_call({rename, Fr, To, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:rename(Handle, Fr, To, DTraceUtag), Handle}; -handle_call({make_dir, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:make_dir(Handle, Name), Handle}; +handle_call({make_dir, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:make_dir(Handle, Name, DTraceUtag), Handle}; -handle_call({del_dir, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:del_dir(Handle, Name), Handle}; +handle_call({del_dir, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:del_dir(Handle, Name, DTraceUtag), Handle}; -handle_call({list_dir, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:list_dir(Handle, Name), Handle}; +handle_call({list_dir, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:list_dir(Handle, Name, DTraceUtag), Handle}; handle_call(get_cwd, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle), Handle}; -handle_call({get_cwd}, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle), Handle}; -handle_call({get_cwd, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle, Name), Handle}; + {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, "TODO-fixme"), Handle}; +handle_call({get_cwd, no_drive, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, DTraceUtag), Handle}; +handle_call({get_cwd, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:get_cwd(Handle, Name, DTraceUtag), Handle}; -handle_call({read_file_info, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle}; +handle_call({read_file_info, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, DTraceUtag), Handle}; +handle_call({read_file_info, Name, Opts, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts, DTraceUtag), Handle}; -handle_call({read_file_info, Name, Opts}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle}; +handle_call({altname, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:altname(Handle, Name, DTraceUtag), Handle}; -handle_call({altname, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:altname(Handle, Name), Handle}; +handle_call({write_file_info, Name, Info, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, DTraceUtag), Handle}; +handle_call({write_file_info, Name, Info, Opts, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts, DTraceUtag), Handle}; -handle_call({write_file_info, Name, Info}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle}; +handle_call({read_link_info, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, DTraceUtag), Handle}; +handle_call({read_link_info, Name, Opts, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts, DTraceUtag), Handle}; -handle_call({write_file_info, Name, Info, Opts}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle}; +handle_call({read_link, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link(Handle, Name, DTraceUtag), Handle}; -handle_call({read_link_info, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle}; +handle_call({make_link, Old, New, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:make_link(Handle, Old, New, DTraceUtag), Handle}; -handle_call({read_link_info, Name, Opts}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle}; +handle_call({make_symlink, Old, New, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:make_symlink(Handle, Old, New, DTraceUtag), Handle}; -handle_call({read_link, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link(Handle, Name), Handle}; - -handle_call({make_link, Old, New}, _From, Handle) -> - {reply, ?PRIM_FILE:make_link(Handle, Old, New), Handle}; - -handle_call({make_symlink, Old, New}, _From, Handle) -> - {reply, ?PRIM_FILE:make_symlink(Handle, Old, New), Handle}; - -handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length}, +handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length, DTraceUtag}, _From, Handle) -> Reply = - case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts]) of + case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts], + DTraceUtag) of {ok, Source} -> SourceReply = case ?PRIM_FILE:open(DestName, - [write, binary | DestOpts]) of + [write, binary | DestOpts], + DTraceUtag) of {ok, Dest} -> DestReply = - ?PRIM_FILE:copy(Source, Dest, Length), - ?PRIM_FILE:close(Dest), + ?PRIM_FILE:copy(Source, Dest, Length, DTraceUtag), + ?PRIM_FILE:close(Dest, DTraceUtag), DestReply; {error, _} = Error -> Error end, - ?PRIM_FILE:close(Source), + ?PRIM_FILE:close(Source, DTraceUtag), SourceReply; {error, _} = Error -> Error diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 3e2202922c..9575762b12 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -70,7 +70,7 @@ %% compile time. -define(PRIM_FILE_call(F, H, A), case H of - [] -> apply(?PRIM_FILE, F, A); + [] -> apply(?PRIM_FILE, F, A -- ["utag"]); _ -> apply(?PRIM_FILE, F, [H | A]) end). @@ -255,31 +255,31 @@ make_del_dir(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_mk-dir"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), - ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), % Make sure we are not in a directory directly under test_server % as that would result in eacess errors when trying to delere '..', % because there are processes having that directory as current. - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), try %% Check that we get an error when trying to create... %% a deep directory ?line NewDir2 = filename:join(RootDir, atom_to_list(?MODULE) ++"_mk-dir-noexist/foo"), - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2, "utag"]), %% a nameless directory - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, ["", "utag"]), %% a directory with illegal name - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir', "utag"]), %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}], "utag"]), %% Maybe this isn't an error, exactly, but worth mentioning anyway: %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), @@ -292,17 +292,17 @@ make_del_dir(Config, Handle, Suffix) -> %% Try deleting some bad directories %% Deleting the parent directory to the current, sounds dangerous, huh? %% Don't worry ;-) the parent directory should never be empty, right? - ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of + ?line case ?PRIM_FILE_call(del_dir, Handle, ["..", "utag"]) of {error, eexist} -> ok; {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), - ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, ["", "utag"]), + ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}], "utag"]), ?line test_server:timetrap_cancel(Dog) after - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir]) + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir, "utag"]) end, ok. @@ -324,7 +324,7 @@ cur_dir_0(Config, Handle) -> %% Find out the current dir, and cd to it ;-) ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), ?line Dir1 = BaseDir ++ "", %% Check that it's a string - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), ?line DirName = atom_to_list(?MODULE) ++ case Handle of [] -> @@ -336,40 +336,40 @@ cur_dir_0(Config, Handle) -> %% Make a new dir, and cd to that ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, DirName), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line io:format("cd to ~s",[NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), %% Create a file in the new current directory, and check that it %% really is created there ?line UncommonName = "uncommon.fil", ?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]), ?line ok = ?PRIM_FILE:close(Fd), - ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), ?line true = lists:member(UncommonName,NewDirFiles), %% Delete the directory and return to the old current directory %% and check that the created file isn't there (too!) ?line expect({error, einval}, {error, eacces}, {error, eexist}, - ?PRIM_FILE_call(del_dir, Handle, [NewDir])), - ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]), - ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"])), + ?line ?PRIM_FILE_call(delete, Handle, [UncommonName, "utag"]), + ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), ?line io:format("cd back to ~s",[Dir1]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), ?line io:format("cd back to ~s",[Dir1]), - ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), ?line false = lists:member(UncommonName,OldDirFiles), %% Try doing some bad things ?line {error, badarg} = - ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}]), + ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}, "utag"]), ?line {error, enoent} = - ?PRIM_FILE_call(set_cwd, Handle, [""]), + ?PRIM_FILE_call(set_cwd, Handle, ["", "utag"]), ?line {error, enoent} = - ?PRIM_FILE_call(set_cwd, Handle, [".......a......"]), + ?PRIM_FILE_call(set_cwd, Handle, [".......a......", "utag"]), ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), %% Still there? @@ -405,10 +405,10 @@ cur_dir_1(Config, Handle) -> ?line case os:type() of {unix, _} -> ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); + ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]); vxworks -> ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); + ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]); {win32, _} -> win_cur_dir_1(Config, Handle) end, @@ -422,7 +422,7 @@ win_cur_dir_1(_Config, Handle) -> %% and try to get current directory for that drive. ?line [Drive, $:|_] = BaseDir, - ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:]]), + ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:], "utag"]), io:format("BaseDir = ~s\n", [BaseDir]), %% Unfortunately, there is no way to move away from the @@ -1027,7 +1027,7 @@ file_write_file_info(Config, Handle, Suffix) -> ?line ok = ?PRIM_FILE:write_file(Name, "hello"), ?line Time = {{1997, 01, 02}, {12, 35, 42}}, ?line Info = #file_info{mode=8#400, atime=Time, mtime=Time, ctime=Time}, - ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info]), + ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info, "utag"]), %% Read back the times. @@ -1050,12 +1050,12 @@ file_write_file_info(Config, Handle, Suffix) -> %% Make the file writable again. ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#600}]), + [Name, #file_info{mode=8#600}, "utag"]), ?line ok = ?PRIM_FILE:write_file(Name, "hello again"), %% And unwritable. ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#400}]), + [Name, #file_info{mode=8#400}, "utag"]), ?line {error, eacces} = ?PRIM_FILE:write_file(Name, "hello again"), %% Write the times again. @@ -1063,7 +1063,7 @@ file_write_file_info(Config, Handle, Suffix) -> ?line NewTime = {{1997, 02, 15}, {13, 18, 20}}, ?line NewInfo = #file_info{atime=NewTime, mtime=NewTime, ctime=NewTime}, - ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo]), + ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo, "utag"]), ?line {ok, ActualInfo2} = ?PRIM_FILE_call(read_file_info, Handle, [Name]), ?line #file_info{atime=NewActAtime, mtime=NewTime, @@ -1081,7 +1081,7 @@ file_write_file_info(Config, Handle, Suffix) -> %% Make the file writeable again, so that we can remove the %% test suites ... :-) ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#600}]), + [Name, #file_info{mode=8#600}, "utag"]), ?line test_server:timetrap_cancel(Dog), ok. @@ -1390,11 +1390,11 @@ delete(Config, Handle, Suffix) -> %% Check that the file is readable ?line {ok, Fd2} = ?PRIM_FILE:open(Name, [read]), ?line ok = ?PRIM_FILE:close(Fd2), - ?line ok = ?PRIM_FILE_call(delete, Handle, [Name]), + ?line ok = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]), %% Check that the file is not readable anymore ?line {error, _} = ?PRIM_FILE:open(Name, [read]), %% Try deleting a nonexistent file - ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]), + ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]), ?line test_server:timetrap_cancel(Dog), ok. @@ -1895,14 +1895,14 @@ make_link(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_make_link"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line Name = filename:join(NewDir, "a_file"), ?line ok = ?PRIM_FILE:write_file(Name, "some contents\n"), ?line Alias = filename:join(NewDir, "an_alias"), ?line Result = - case ?PRIM_FILE_call(make_link, Handle, [Name, Alias]) of + case ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; ok -> @@ -1913,12 +1913,12 @@ make_link(Config, Handle, Suffix) -> %% since they are not used on symbolic links. ?line {ok, Info} = - ?PRIM_FILE_call(read_link_info, Handle, [Name]), + ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]), ?line {ok, Info} = - ?PRIM_FILE_call(read_link_info, Handle, [Alias]), + ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]), ?line #file_info{links = 2, type = regular} = Info, ?line {error, eexist} = - ?PRIM_FILE_call(make_link, Handle, [Name, Alias]), + ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]), ok end, @@ -1956,30 +1956,30 @@ symlinks(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_make_symlink"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line Name = filename:join(NewDir, "a_plain_file"), ?line ok = ?PRIM_FILE:write_file(Name, "some stupid content\n"), ?line Alias = filename:join(NewDir, "a_symlink_alias"), ?line Result = - case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of + case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias, "utag"]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; ok -> ?line {ok, Info1} = - ?PRIM_FILE_call(read_file_info, Handle, [Name]), + ?PRIM_FILE_call(read_file_info, Handle, [Name, "utag"]), ?line {ok, Info1} = - ?PRIM_FILE_call(read_file_info, Handle, [Alias]), + ?PRIM_FILE_call(read_file_info, Handle, [Alias, "utag"]), ?line {ok, Info1} = - ?PRIM_FILE_call(read_link_info, Handle, [Name]), + ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]), ?line #file_info{links = 1, type = regular} = Info1, ?line {ok, Info2} = - ?PRIM_FILE_call(read_link_info, Handle, [Alias]), + ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]), ?line #file_info{links=1, type=symlink} = Info2, ?line {ok, Name} = - ?PRIM_FILE_call(read_link, Handle, [Alias]), + ?PRIM_FILE_call(read_link, Handle, [Alias, "utag"]), ok end, @@ -2003,7 +2003,7 @@ list_dir_limit(Config) when is_list(Config) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE)++"_list_dir_limit"), ?line {ok, Handle1} = ?PRIM_FILE:start(), - ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir, "utag"]), Ref = erlang:start_timer(MaxTime*1000, self(), []), ?line Result = list_dir_limit_loop(NewDir, Handle1, Ref, MaxNumber, 0), ?line Time = case erlang:cancel_timer(Ref) of @@ -2054,7 +2054,7 @@ list_dir_limit_loop(Dir, Handle, Ref, N, Cnt) -> end. list_dir_check(Dir, Handle, Cnt) -> - case ?PRIM_FILE:list_dir(Handle, Dir) of + case ?PRIM_FILE:list_dir(Handle, Dir, "utag") of {ok, ListDir} -> case length(ListDir) of Cnt -> |