Kernel based rename undo
Posted Apr 12, 2009 4:52 UTC (Sun) by
bojan (subscriber, #14302)
In reply to:
Kernel based rename undo by bojan
Parent article:
Linux Storage and Filesystem workshop, day 1
A more robust version below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <aio.h>
#include <errno.h>
/* XXX this is just a demo, no error checking */
static int sd=-1;
static int count=0;
static char filler[2]={0,0};
/* locks */
static struct flock
fwl={.l_type=F_WRLCK,.l_whence=SEEK_SET,.l_start=0,.l_len=1},
ful={.l_type=F_UNLCK,.l_whence=SEEK_SET,.l_start=0,.l_len=1},
bwl={.l_type=F_WRLCK,.l_whence=SEEK_SET,.l_start=1,.l_len=1},
brl={.l_type=F_RDLCK,.l_whence=SEEK_SET,.l_start=1,.l_len=1},
bul={.l_type=F_UNLCK,.l_whence=SEEK_SET,.l_start=1,.l_len=1};
static void aiodone(int signum,siginfo_t *info,void *context){
/* signal counter down */
count--;
}
#define BUF_SIZE 50
static void config(struct aiocb *cb){
int fd;
ssize_t len;
char buf[BUF_SIZE];
/* critical section */
while(fcntl(sd,F_SETLKW,&fwl));
/* don't care if it fails, any version is OK */
link("foo","foo~");
/* read existing file */
fd=open("foo",O_RDONLY);
len=read(fd,buf,BUF_SIZE);
close(fd);
/* write to new file */
fd=open("foo.new",O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
write(fd,buf,len);
/* AIO control block setup */
memset(cb,0,sizeof(*cb));
cb->aio_sigevent.sigev_notify=SIGEV_SIGNAL;
cb->aio_sigevent.sigev_signo=SIGRTMIN;
cb->aio_fildes=fd;
/* signal counter up */
count++;
/* initiate sync and close */
aio_fsync(O_SYNC,cb);
close(fd);
/* put the new file in place */
rename("foo.new","foo");
/* end critical section */
while(fcntl(sd,F_SETLKW,&ful));
}
#define LOOPS 10
#define TRIES 20
int main(int argc,char **argv){
int i;
struct aiocb cb[LOOPS];
struct sigaction act;
/* setup shared file, restore */
if((sd=shm_open("foo",O_RDWR|O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1){
int tries=TRIES;
struct stat f;
/* not the first to arrive, open and wait for restore */
sd=shm_open("foo",O_RDWR,S_IRUSR|S_IWUSR);
fstat(sd,&f);
while(tries-- && f.st_size<sizeof(filler)){
sleep(1);
fstat(sd,&f);
}
/* something's really screwed */
if(!tries)
return 1;
} else{ /* first to arrive, restore */
/* don't care if we fail */
if(!rename("foo~","foo"))
fprintf(stderr,"Restored.\n");
/* setup lock file */
write(sd,&filler,sizeof(filler));
}
/* signal handler setup */
memset(&act,0,sizeof(act));
act.sa_flags=SA_SIGINFO;
act.sa_sigaction=aiodone;
sigaction(SIGRTMIN,&act,NULL);
/* we need the backup file to be there */
while(fcntl(sd,F_SETLKW,&brl));
/* program may run config many times */
for(i=0;i<LOOPS;i++){
config(&cb[i]);
/* do something really useful here */
}
/* wait for AIO completion */
while(count)
sleep(1);
/* unlock the backup file */
while(fcntl(sd,F_SETLKW,&bul));
/* try to remove backup file */
if(!fcntl(sd,F_SETLK,&fwl)){
if(!fcntl(sd,F_SETLK,&bwl)){
unlink("foo~");
while(fcntl(sd,F_SETLKW,&bul));
}
while(fcntl(sd,F_SETLKW,&ful));
}
/* clean up shared memory */
close(sd);
return 0;
}
(
Log in to post comments)