For some reason I can't get open() to open a file. Here's my code.
static int context_ctor(X86Context *ctx)
{
char file[512];
memset(ctx, 0, sizeof(X86Context));
sprintf(file, "%s.%d", "test", getpid());
ctx->fp = open(file, O_RDWR);
if(ctx->fp < 0) {
printf("errno %d %s\n", errno, file);
return VISUAL_ERROR_GENERAL;
}
ctx->buf = mmap(0, MAXFILESIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, ctx->fp, 0);
printf("context_ctor: %p\n", ctx->buf);
close(ctx->fp);
exit(0);
}
And here's the output:
errno 2 test.12356
Looking up the error code reveals:
[EACCES]
Permission denied.
I know I have permission to read/write/execute files in this directory. I even tried /tmp/test.pid. Any idea?
If you're trying to create a new file you need to use O_CREAT, so:
ctx->fp = open(file, O_CREATE | O_RDWR);
By the way, you may want to use strerror(errno) to show your errors
Related
I'm reading the source code in https://wayland-book.com/surfaces/shared-memory.html .
The author create a shared memory using shm_open(), and shm_unlink() it immediately, then ftruncate() the fd to a specific size, mmap() the fd and fill the region with pixels.
I'm so confused why the fd still available after shm_unlink().
according to the man page:
The operation of shm_unlink() is analogous to unlink(2): it removes a shared memory object name, and, once all processes have unmapped the object, de-allocates and destroys the contents of the associated memory region. After a successful shm_unlink(), attempts to shm_open() an object with the same name will fail (unless O_CREAT was specified, in which case a new, distinct object is created).
so shm_unlink() will cause the memory destroyed because there is no process mmap
the region. But how fd still avaliable?
here is the code:
static int
create_shm_file(void)
{
int retries = 100;
do {
char name[] = "/wl_shm-XXXXXX";
randname(name + sizeof(name) - 7);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd >= 0) {
shm_unlink(name); // unlink immediately
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static int
allocate_shm_file(size_t size)
{
int fd = create_shm_file();
if (fd < 0)
return -1;
int ret;
do {
ret = ftruncate(fd, size); //why the fd still available?
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
return -1;
}
return fd;
}
//after above, there was mmap
uint32_t *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Note: the actual problem was with using fork() function. So the solution is found.
//create shared memoery
int shmfd;
void *shared_memory = (void *)0;
shmfd = shm_open("/shm2_rev_to_upp", O_RDWR | O_CREAT | O_EXCL, 0666); //reverse to upper
if (shmfd == -1) {
perror("shm_open");
exit(1);
}
if(ftruncate(shmfd, sizeof(struct shared_use_st)) == -1){
perror("ftruncate");
exit(1);
}
shared_memory = mmap(NULL, sizeof(struct shared_use_st), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if(shared_memory == MAP_FAILED){
perror("mmap");
exit(1);
}
//some code here
munmap(shared_memory, sizeof(struct shared_use_st));
shm_unlink("/shm2_rev_to_upp");
close(shmfd);
I got this error in the runtime
shm_open: File exists
Then shm_open() return -1 why is that?!!
Note that the first couple of times I run the program, the error does not show up!!
How can I fix this problem?!
The man page explains the various error codes:
EEXIST: Both O_CREAT and O_EXCL were specified to shm_open() and the shared memory object specified by name already exists.
shmfd = shm_open("/shm2_rev_to_upp", O_RDWR | O_CREAT | O_EXCL, 0666);
modify: shmfd = shm_open("/shm2_rev_to_upp", O_RDWR | O_CREAT, 0666);
I want to share memory using a file descriptor with another process created via fork.
The problem is that I get different address regions from mmap.
I want that mmap returns the same address value. Only in such case I can be sure that I really share the memory.
Probably it is possible to use MAP_FIXED flag to mmap, but how to get memory address from shm_open?
Is it possible to share memory via shm_open at all?
Maybe shmget must be used instead?
This is the minimal working example:
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
/* Create a new memory object */
int fd = shm_open( "/dummy", O_RDWR | O_CREAT, 0777 );
if(fd == -1) {
fprintf(stderr, "Open failed:%m\n");
return 1;
}
/* Set the memory object's size */
size_t size = 4096; /* minimal */
if (ftruncate(fd, size) == -1) {
fprintf(stderr, "ftruncate: %m\n");
return 1;
}
void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) return 1;
void *ptr2 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr2 == MAP_FAILED) return 1;
printf("%p\n%p\n", ptr, ptr2);
return 0;
}
Compile it with gcc test.c -lrt.
This is the output:
0x7f3247a78000
0x7f3247a70000
EDIT
If I try to use method described in comment, child does not see changes in memory made by parent. Why? This is how I do it:
In parent:
shm_data = mmap(NULL, shm_size, PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
...
snprintf(shared_memory, 20, "%p", shm_data);
execl("/path/to/prog", "prog", shared_memory, (char *) NULL);
In child:
...
void *base_addr;
sscanf(argv[1], "%p", (void **)&base_addr);
shm_data = mmap(base_addr, shm_size, PROT_READ, MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED, -1, 0);
...
EDIT2
See also this question: How to get memory address from memfd_create?
I was trying to read/write a file from my kernel module (I know it is dangerous and not suggested at all, but I need to do it for various reasons)
I followed this answer How to read/write files within a Linux kernel module?, and it works fine.
This is the code that I execute to test if the basic functions work:
void test_file(){
struct file * f = file_open("./test.txt", O_CREAT | O_RDWR |
O_APPEND, S_IRWXU | S_IRWXG | S_IRWXO);
if(f != NULL){
char arr[100];
char * str = "I just wrote something";
file_write(f,0, str, strlen(str));
memset(arr, '\0', 100);
file_read(f, 0, arr, 20);
printk(KERN_INFO "Read %s\n",arr);
file_close(f);
}else{
printk(KERN_ERR "Error! Cannot write into file\n");
}
}
If I execute this code inside my __init function, test.txt is created/updated inside the current folder where the .ko file is.
However, I noticed that if I execute this code in a new kthread, the file is created in / folder, and I need to provide the absolute path in order to get it in the current location.
void test_function(){
test_file(); // creates test.txt in /
}
static int __init file_init(void) {
struct task_struct * test_thread = kthread_run((void *)test_function, NULL, "Test");
test_file(); // creates test.txt in .
}
module_init(file_init)
Definitions of file_write, file_read, file_close and file_open are given in the linked stackoverflow answer
Anybody knows how to give a relative path also in the kthread?
This is what I did:
struct file * f;
void test_file(){
if(f != NULL){
char arr[100];
char * str = "I just wrote something";
file_write(f,0, str, strlen(str));
memset(arr, '\0', 100);
file_read(f, 0, arr, 20);
printk(KERN_INFO "Read %s\n",arr);
file_close(f);
}else{
printk(KERN_ERR "Error! Cannot open file\n");
}
}
void test_function(){
test_file(); // access the file from the kthread
}
static int __init file_init(void) {
// Create and open the file in user space
f = file_open("./test.txt", O_CREAT | O_RDWR | O_APPEND, \
S_IRWXU | S_IRWXG | S_IRWXO);
struct task_struct * test_thread = kthread_run((void *)test_function, \
NULL, "Test");
}
module_init(file_init)
I have a question when I use msync. Thank you very much for your help!
In brief, I mmap file A, and modify it, and the msync, but the st_mtime doesn't change. even munmap file A and exit the process, the st_mtime is also unchanged.
The following is the code.
int main() {
const char *file_name = "txt";
int ret = -1;
int fd = open(file_name, O_RDWR, 0666);
if (fd < 0) {
printf("FATAL, Fail to open file[%s]\n", file_name);
return -1;
}
struct stat st;
fstat(fd, &st);
void * buffer = mmap(NULL, st.st_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (MAP_FAILED == buffer) {
printf("FATAL, Fail to mmap, file[%s], size[%d]\n",
file_name, st.st_size);
return -1;
}
printf("m_time[%d]\n", st.st_mtime);
for (int i=0; i<10;i++) {
int *ptr = (int *)buffer;
printf("%d\n", *ptr);
*ptr += 1;
sleep(1);
ret = msync(buffer, st.st_size, MS_ASYNC);
if (0 != ret) {
printf("FATAL, Fail to msync, file[%s], size[%d]\n",
file_name, st.st_size);
return -1;
}
fstat(fd, &st);
printf("m_time[%d]\n", st.st_mtime);
}
ret = munmap(buffer, st.st_size);
if (0 != ret) {
printf("FATAL, Fail to munmap, file[%s], size[%d]\n",
file_name, st.st_size);
return -1;
}
fstat(fd, &st);
printf("m_time[%d]\n", st.st_mtime);
fsync(fd);
fstat(fd, &st);
printf("m_time[%d]\n", st.st_mtime);
return 0;
}
The relevant excerpt of the mmap manpage is:
The st_ctime and st_mtime field for a file mapped with PROT_WRITE and MAP_SHARED will be updated after a write to the mapped region, and before a subsequent msync(2) with the MS_SYNC or MS_ASYNC flag, if one occurs.
That means that, in your program, st_mtime might be updated anytime between the line which reads
*ptr += 1`
and and the line which reads
ret = msync(buffer, st.st_size, MS_ASYNC);
Your sleep(1) is in between those lines, which means that by the time the sleep occurs, the st_mtime might have already been modified. So when you fstat the file a second time, you might be getting the same value as when you statted it the first time, just because not enough time has elapsed.
Try putting your sleep(1) before the *ptr += 1. This should guarantee that at least one second elapses between the original fstat and the update to the st_mtime.
Looks like a fix is on the way.
http://thread.gmane.org/gmane.linux.kernel/1549524/focus=55700