0

I need to understand some things about direct I/O in C. I have a toy code that uses direct I/O to write a character array and it works just fine:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>


#define MSG_SIZE 4500
#define BLOCK_SIZE 4096

int main(int argc, char **argv) {

  char thefile[64];
  int fd;
  int write_success, bytes_to_write, block_size=BLOCK_SIZE;

  // set array size to some multiple of BLOCKSIZE:
  bytes_to_write = ((MSG_SIZE + block_size - 1)/block_size)*block_size;
  char message[bytes_to_write]  __attribute__ ((aligned(BLOCKSIZE)));

  memset(message, 0, bytes_to_write);
  sprintf(message,"The curfew tolls the knell of parting day");
  printf("%s\n", message);

  sprintf(thefile, "diotestfile.dat");

  if ((fd = open(thefile,O_DIRECT | O_RDWR | O_CREAT, S_IRWXU)) == -1) {
          printf("error opening file\n");
          exit(1);
  }
  printf("%s\n", strerror(errno));
  write_success = write(fd, message, bytes_to_write);
  printf("write succes?  %s\n", strerror(errno));

  close(fd);


}

A cat of the output file gives the message. But I need to be able to do this with a pointer instead an array. If I redefine message as a pointer, that is, I replace

char message[bytes_to_write]  __attribute__ ((aligned(BLOCKSIZE)));
memset(message, 0, bytes_to_write);

with

  char *__attribute__ ((aligned(BLOCKSIZE))) message;
  message = (char *__attribute__ ((aligned(BLOCKSIZE))))calloc(bytes_to_write, sizeof(char));

then the write function returns an error of invalid argument.

The things that haven't worked so far are trying several different alignment sizes, casting message to a void pointer in write(), and defining message as

char *__attribute__ ((aligned(BLOCKSIZE))) message;

instead of

char *__attribute__ ((aligned(BLOCKSIZE))) message;

Anyone see what I'm doing wrong?

bob.sacamento
  • 6,283
  • 10
  • 56
  • 115
  • `calloc()` doesn't know the alignment requirement. – Barmar Jan 29 '21 at 22:54
  • My guess is you're going to have to overallocate your `malloc`/`calloc` allocation, then align it yourself, by adding something the the pointer (discarding bytes at the beginning) until you get a pointer to somewhere near the beginning of the block, that satisfies the direct I/O requirements, and also still gives you enough space. – Steve Summit Jan 29 '21 at 22:55
  • Declaring the alignment of the pointer variable doesn't make the memory it points to be aligned. – Barmar Jan 29 '21 at 22:56
  • That is, `char *message = malloc(size + SLOP);`, immediately followed by `message += offset;`, where `offset` is computed such that the new value of `message` satisfies the alignment requirements, and `SLOP >= offset` (for any possible value of `offset`). – Steve Summit Jan 29 '21 at 22:58
  • But really: see the dup question that Barmar linked; it explains all of this, and more. – Steve Summit Jan 29 '21 at 23:13

0 Answers0