1

I'm trying to check if a file on a jffs2 fs exist from a kernel space. I have a Barrier Breaker OpenWrt with a 3.10.14 Linux kernel. (There's an MTD subsystem in use, so I have pseudo block devices for partitions on a NAND flash (/dev/mtdblock1, ...12).)

(I'm implementing some upgrading logic which requires keeping some state between reboots, to store this state, I use the file.)

To check a file existence I just try to open the file (without an O_CREAT flag) and make a decision based on a result of opening. I use the next article about opening a file from within kernel: Read/write files within a Linux kernel module.

I'm able to check a file existence using this approach, but this file is placed not on a rootfs partition, so I have to mount that partition before I can open the file on it. I'm able to mount the partition, open file (to check it existence) and close it, if it was opened, but failed to un-mount it: I got an error -16: EBUSY which, as I guess, means that someone else keep using this block device/mount point. So a question who can keep a reference on it?

I think it's a bad idea, but just to test, I tried to un-mount forcibly with an MNT_FORCE, but, as this article https://linux.die.net/man/2/umount states that this option only for NFS fs, nothing changed.

Here's a code:

/* lool at https://stackoverflow.com/questions/1184274/read-write-files-within-a-linux-kernel-module */
static struct file *file_open( const char *path, int flags, int rights )
{
  struct file *filp = NULL;
  mm_segment_t oldfs;
  int err = 0;

  oldfs = get_fs();
  set_fs( get_ds() );

  filp = filp_open( path, flags, rights );

  set_fs( oldfs );

  if( IS_ERR( filp ) )
  {
    err = PTR_ERR( filp );
    return NULL;
  }

  return filp;
}

bool need_to_switch_to_me_upgrade_mode( void )
{
  struct file* me_upgrade_finished_file;
  dev_t me_upgrade_dev;
  char full_name[256] = { 0 };
  bool result;
  int err;

  const char* me_upgrade_dir = "/me_upgrade";
  const char* me_upgrade_dev_name = "/dev/me_upgrade";

  const char* me_upgrade_finished_flag = "/etc/me_upgrade_finished";

  // /dev/mtdblock6
  const char* me_upgrade_finished_flag_partition = "/dev/mtdblock" str( RECOVERY_ROOTFS_DATA_MTD_PART_NUM ); 

  err = sys_mkdir( (const char __user __force *) me_upgrade_dir, 0700 );
  if( err < 0 )
    panic( "fail to mkdir %s\n", me_upgrade_dir );

  me_upgrade_dev = name_to_dev_t( me_upgrade_finished_flag_partition );
  err = create_dev( me_upgrade_dev_name, me_upgrade_dev );
  if( err < 0 )
    panic( "fail to create_dev %s\n", me_upgrade_dev_name );

  err = sys_mount( me_upgrade_dev_name, me_upgrade_dir, "jffs2", MS_SILENT, NULL );
  if( err < 0 )
    panic( "fail to mount %s on to %s, err: %d\n", me_upgrade_dev_name, me_upgrade_dir, err );

  strlcat( full_name, me_upgrade_dir, sizeof( full_name ) );
  strlcat( full_name, me_upgrade_finished_flag, sizeof( full_name ) );

  me_upgrade_finished_file = file_open( full_name, O_RDONLY, 0 );
  if( !me_upgrade_finished_file )
  {
    printk( "fail to open a %s file\n", full_name );
    result = true;
  }
  else
  {
    printk( "success to open a file\n" );
    result = false;
  }

  if( me_upgrade_finished_file )
  {
    err = filp_close( me_upgrade_finished_file, NULL );
    printk( "filp_close returned: %d\n", err );
  }

  err = sys_umount( me_upgrade_dir, MNT_DETACH );
  printk( "sys_umount returned: %d\n", err );

  sys_unlink( me_upgrade_dev_name );  // destroy_dev( me_upgrade_dev_name );
  sys_rmdir( me_upgrade_dir );

  return result;
}

This code is called from a kernel_init_freeable function (init/main.c) after we have MTD subsystem initialized (after do_basic_setup() and before a rootfs gets mounted).

So the questions are:

  • who can keep using a block device/mount point after I closed a file?
  • is any other ways to check if file exist from within kernel?

I have a second option, just to place my state in a partition without any fs, and check it by performing a raw access to the flash memory, but this approach will require significant changes to user code I have now, so I'm trying to avoid it...

P.S. I tried to change a call to file_open/filp_close by sys_open/sys_close (with the same arguments), but nothing changed...

sergs
  • 123
  • 1
  • 12

0 Answers0