c - Linux : setting locale at runtime and interprocess dependencies -


i stuck in strange problem.

i have 2 scripts (c program executables) running on arm linux machine mounting same usb device (containing chinese character filenames) on 2 different paths, device inserted.

int mount(const char *source, const char *target,                  const char *filesystemtype, unsigned long mountflags,                  const void *data); 

in last parameter, script passes "utf8" , script b passes 0.

so, insert usb device, scripts race mount device.

if script mounts first (which passes utf8 parameter), proper filenames. mount command output [notice second mount has utf8 parameter, if not passed. why?]

/dev/sdb1 on /home/root/script1 type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-r o) /dev/sdb1 on /home/root/script2 type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed ,utf8,errors=remount-ro) 

but if script b mounts first(which passes 0 last parameter mount), broken filenames ?????.mp3 readdir(). mount command output.

/dev/sdb1 on /home/root/script2 type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro) /dev/sdb1 on /home/root/script1 type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed ,errors=remount-ro)          

edit

this basic mount code of both scripts developed testing(only difference in last mount argument). both scripts executed on reboot using service.

//mount device         ret = mount("/dev/sda1", "/home/root/script1/", "vfat", 1, "utf8");         if (ret == 0) {                 fprintf(stdout,"mount() succeeded.\n");                 sleep(2000);         } else {                 ret = mount("/dev/sdb1", "/home/root/script1/", "vfat", 1, "utf8");                 if(ret == 0)                 {                     fprintf(stdout,"mount() succeeded\n");                     sleep(2000);                 }                 else                 {                     fprintf(stdout,"/dev/sdb1 mount() failed: %d, %s\n", errno, strerror(errno));                     ret = mount("/dev/sdc1", "/home/root/script1/", "vfat", 1, "utf8");                     if(ret == 0)                     {                         fprintf(stdout,"mount() succeeded\n");                         sleep(2000);                     }                     else                         fprintf(stdout,"mount() failed: %d, %s\n", errno, strerror(errno));                 }         } 

generally speaking, should never mount same filesystem twice -- if os drivers decide write twice same block, you'll filesystem corruption. use bind-mounts in such cases.

linux, however, smart enough -- reuse older filesystem mount super_block (with mountpoint flags) a location.

i couldn't find in documentation, traceable through kernel source in sget() called mount_bdev():

hlist_for_each_entry(old, &type->fs_supers, s_instances) {         if (!test(old, data))                 continue;         if (!grab_super(old))                 goto retry;         if (s) {                 up_write(&s->s_umount);                 destroy_super(s);                 s = null;         }         return old; } 

in snippet it'll seek previous instance of super_block corresponding block device, , if exists -- returns it.


some practical proof using systemtap:

# stap -e 'probe kernel.function("sget").return {         sb = $return;         active = @cast(sb, "super_block")->s_active->counter;         fsi = @cast(sb, "super_block")->s_fs_info;         uid = fsi == 0 ? -1             : @cast(fsi, "msdos_sb_info", "vfat")->options->fs_uid;         printf("%p active=%d uid=%d\n", sb, active, uid);     }' 

setting uid in second mount doesn't alter option, increases number of active mounts (obvious):

  # mount /dev/sdd1 /tmp/mnt1   0xffff8803ce87e800 active=1 uid=-1   # mount -o uid=1000 /dev/sdd1 /tmp/mnt2   0xffff8803ce87e800 active=2 uid=0 

mounting in reverse order inherits mount options:

  # mount -o uid=1000 /dev/sdd1 /tmp/mnt2   0xffff8803cc609c00 active=1 uid=-1   # mount /dev/sdd1 /tmp/mnt1   0xffff8803cc609c00 active=2 uid=1000 

if wish know responsible such behavior, ask linus, similiar code exists since 0.11:

struct super_block * get_super(int dev) {     struct super_block * s;      if (!dev)         return null;     s = 0+super_block;     while (s < nr_super+super_block)         if (s->s_dev == dev) {             wait_on_super(s);             if (s->s_dev == dev)                 return s;             s = 0+super_block;         } else             s++;     return null; } 

(but when code in charge, sys_mount() explicitly checked no other mountpoints exist superblock).

you can possibly try ask question @ lkml.


Comments

Popular posts from this blog

angularjs - ADAL JS Angular- WebAPI add a new role claim to the token -

php - CakePHP HttpSockets send array of paramms -

node.js - Using Node without global install -