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
Post a Comment