コード例 #1
0
ファイル: balloc.c プロジェクト: dmgerman/original
unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
	unsigned goal, unsigned count, int * err )
{
	struct super_block * sb;
	struct ufs_sb_private_info * uspi;
	struct ufs_super_block_first * usb1;
	struct buffer_head * bh;
	unsigned cgno, oldcount, newcount, tmp, request, i, result;
	unsigned swab;
	
	UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
	
	sb = inode->i_sb;
	swab = sb->u.ufs_sb.s_swab;
	uspi = sb->u.ufs_sb.s_uspi;
	usb1 = ubh_get_usb_first(USPI_UBH);
	*err = -ENOSPC;

	lock_super (sb);
	
	tmp = SWAB32(*p);
	if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
		ufs_warning (sb, "ufs_new_fragments", "internal warning"
			" fragment %u, count %u", fragment, count);
		count = uspi->s_fpb - ufs_fragnum(fragment); 
	}
	oldcount = ufs_fragnum (fragment);
	newcount = oldcount + count;

	/*
	 * Somebody else has just allocated our fragments
	 */
	if (oldcount) {
		if (!tmp) {
			ufs_error (sb, "ufs_new_fragments", "internal error, "
				"fragment %u, tmp %u\n", fragment, tmp);
			return (unsigned)-1;
		}
		if (fragment < inode->u.ufs_i.i_lastfrag) {
			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
			unlock_super (sb);
			return 0;
		}
	}
	else {
		if (tmp) {
			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
			unlock_super(sb);
			return 0;
		}
	}
	
	/*
	 * There is not enough space for user on the device
	 */
	if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
		unlock_super (sb);
		UFSD(("EXIT (FAILED)\n"))
		return 0;
	} 
コード例 #2
0
ファイル: namei.c プロジェクト: liexusong/linux2.0-comment
int xiafs_rmdir(struct inode * dir, const char * name, int len)
{
    int retval;
    struct inode * inode;
    struct buffer_head * bh;
    struct xiafs_direct * de, * de_pre;

    inode = NULL;
    bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
    retval = -ENOENT;
    if (!bh)
        goto end_rmdir;
    retval = -EPERM;
    if (!(inode = iget(dir->i_sb, de->d_ino)))
        goto end_rmdir;
    if ((dir->i_mode & S_ISVTX) && !fsuser() &&
            current->fsuid != inode->i_uid &&
            current->fsuid != dir->i_uid)
        goto end_rmdir;
    if (inode->i_dev != dir->i_dev)
        goto end_rmdir;
    if (inode == dir)	/* we may not delete ".", but "../dir" is ok */
        goto end_rmdir;
    if (!S_ISDIR(inode->i_mode)) {
        retval = -ENOTDIR;
	goto end_rmdir;
    }
    if (!empty_dir(inode)) {
        retval = -ENOTEMPTY;
	goto end_rmdir;
    }
    if (inode->i_count > 1) {
        retval = -EBUSY;
	goto end_rmdir;
    }
    if (inode->i_nlink != 2)
        printk("XIA-FS: empty directory has nlink!=2 (%s %d)\n", WHERE_ERR);
    xiafs_rm_entry(de, de_pre);
    mark_buffer_dirty(bh, 1);
    inode->i_nlink=0;
    inode->i_dirt=1;
    dir->i_nlink--;
    inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    dir->i_dirt=1;
    retval = 0;
end_rmdir:
    iput(dir);
    iput(inode);
    brelse(bh);
    return retval;
}
コード例 #3
0
ファイル: namei.c プロジェクト: liexusong/linux2.0-comment
int xiafs_unlink(struct inode * dir, const char * name, int len)
{
    int retval;
    struct inode * inode;
    struct buffer_head * bh;
    struct xiafs_direct * de, * de_pre;

repeat:
    retval = -ENOENT;
    inode = NULL;
    bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
    if (!bh)
        goto end_unlink;
    if (!(inode = iget(dir->i_sb, de->d_ino)))
        goto end_unlink;
    retval = -EPERM;
    if (S_ISDIR(inode->i_mode))
        goto end_unlink;
    if (de->d_ino != inode->i_ino) {
        iput(inode);
	brelse(bh);
	current->counter = 0;
	schedule();
	goto repeat;
    }
    if ((dir->i_mode & S_ISVTX) && !fsuser() &&
	    current->fsuid != inode->i_uid &&
	    current->fsuid != dir->i_uid)
        goto end_unlink;
    if (!inode->i_nlink) {
        printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR);
	inode->i_nlink=1;
    }
    xiafs_rm_entry(de, de_pre);
    mark_buffer_dirty(bh, 1);
    inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    dir->i_dirt = 1;
    inode->i_nlink--;
    inode->i_dirt = 1;
    retval = 0;
end_unlink:
    brelse(bh);
    iput(inode);
    iput(dir);
    return retval;
}
コード例 #4
0
ファイル: open.c プロジェクト: rohsaini/mkunity
asmlinkage int sys_chroot(const char * filename)
{
	struct inode * inode;
	int error;

	error = namei(filename,&inode);
	if (error)
		return error;
	if (!S_ISDIR(inode->i_mode)) {
		iput(inode);
		return -ENOTDIR;
	}
	if (!fsuser()) {
		iput(inode);
		return -EPERM;
	}
	iput(current->fs->root);
	current->fs->root = inode;
	return (0);
}
コード例 #5
0
ファイル: namei.c プロジェクト: chinnyannieb/empeg-hijack
int rmdir_not_allowed (struct inode * dir, struct reiserfs_dir_entry * de, struct inode * inode)
{
  if ((dir->i_mode & S_ISVTX) && !fsuser() &&
      current->fsuid != inode->i_uid &&
      current->fsuid != dir->i_uid)
    return -EPERM;

  if (inode->i_dev != dir->i_dev)
    return -EPERM;

  if (inode == dir)	/* we may not delete ".", but "../dir" is ok */
    return -EPERM;

  if (!S_ISDIR(inode->i_mode))
    return -ENOTDIR;

  if (!reiserfs_empty_dir(inode))
    return -ENOTEMPTY;

  if (de->de_objectid != inode->i_ino)
    return -ENOENT;

  return 0;
}
コード例 #6
0
ファイル: namei.c プロジェクト: chinnyannieb/empeg-hijack
/* 
 * process, that is going to call fix_nodes/do_balance must hold only
 * one path. If it holds 2 or more, it can get into endless waiting in
 * get_empty_nodes or its clones 
 */
static int do_reiserfs_rename (struct reiserfs_transaction_handle *th, struct inode * old_dir, struct dentry *old_dentry,
			       struct inode * new_dir, struct dentry *new_dentry)
{
  int retval;
  struct path old_entry_path, new_entry_path, dot_dot_entry_path;
  struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
  struct inode * old_inode, * new_inode;
  int new_entry_added = 0;

  init_path (&old_entry_path);
  init_path (&new_entry_path);
  init_path (&dot_dot_entry_path);
  goto start_up;

try_again:
  current->policy |= SCHED_YIELD;
  schedule();
	
start_up:
  old_inode = new_inode = NULL;
  dot_dot_de.de_bh = 0;
  new_de.de_bh = 0;

  /* 
   * look for the old name in old directory 
   */
  retval = -ENOENT;
  old_de.de_gen_number_bit_string = 0;
  if (reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de) == POSITION_NOT_FOUND)
    goto end_rename;

  pathrelse (&old_entry_path);

  old_inode = old_dentry->d_inode;
  retval = -EPERM;

  if ((old_dir->i_mode & S_ISVTX) && 
      current->fsuid != old_inode->i_uid &&
      current->fsuid != old_dir->i_uid && !fsuser())
    goto end_rename;

  new_inode = new_dentry->d_inode;

  /* look for the new entry in target directory */
  new_de.de_gen_number_bit_string = 0;
  if (reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de) == POSITION_FOUND) {
    if (!new_inode) {
      printk ("do_reiserfs_rename: new entry found, inode == 0 though\n");
    }
    /* this entry already exists, we can just set key of object */
    new_entry_added = 1;
  } else {
#ifdef REISERFS_CHECK
    if (new_entry_added) {
      if (new_de.de_namelen != new_dentry->d_name.len || memcmp (new_de.de_name, new_dentry->d_name.name, new_de.de_namelen) ||
	  de_visible (new_de.de_deh))
	reiserfs_panic (old_dir->i_sb, "vs-7045: reiserfs_rename: suspicious entry found");
    }
#endif /* REISERFS_CHECK */
  }
  pathrelse (&new_entry_path);


  if (new_inode == old_inode) {
    retval = 0;
    goto end_rename;
  }

  if (new_inode && S_ISDIR(new_inode->i_mode)) {
    /* new name exists and points to directory */
    retval = -EISDIR;
    if (!S_ISDIR(old_inode->i_mode))
      goto end_rename;
    retval = -EINVAL;
    if (is_subdir (new_dentry, old_dentry))
      goto end_rename;
    retval = -ENOTEMPTY;
    if (!reiserfs_empty_dir (new_inode))
      goto end_rename;
    retval = -EBUSY;
    if (new_inode->i_count > 1)
      goto end_rename;
  }

  retval = -EPERM;
  if (new_inode && (new_dir->i_mode & S_ISVTX) && 
      current->fsuid != new_inode->i_uid &&
      current->fsuid != new_dir->i_uid && !fsuser())
    goto end_rename;

  if (S_ISDIR(old_inode->i_mode)) {
    /* old name points to directory */
    retval = -ENOTDIR;
    if (new_inode && !S_ISDIR(new_inode->i_mode))
      goto end_rename;

    retval = -EINVAL;
    if (is_subdir(new_dentry, old_dentry))
      goto end_rename;

    retval = -EIO;
    /* directory is renamed, its parent directory will be changed, so find ".." entry */
    dot_dot_de.de_gen_number_bit_string = 0;
    if (reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de) == POSITION_NOT_FOUND)
      goto end_rename;
    if (dot_dot_de.de_objectid != old_dir->i_ino)
      goto end_rename;
    pathrelse (&dot_dot_entry_path);

    retval = -EMLINK;
    if (!new_inode && new_dir->i_nlink >= REISERFS_LINK_MAX)
      goto end_rename;
  }
  
  if (new_entry_added == 0) {
    /* add new entry if we did not do it, but do not mark it as visible */
    retval = reiserfs_add_entry (th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, INODE_PKEY (old_inode), &new_de, 0);
    if (retval)
      goto end_rename;
    if_in_ram_update_sd (th, new_dir);
    new_entry_added = 1;
    goto try_again;
  }


  /* 
   * look for old name, new name and ".." when renaming directories again
   */
  if (reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de) == POSITION_NOT_FOUND)
    reiserfs_panic (old_dir->i_sb, "vs-7050: reiserfs_rename: old name not found");
  if (reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de) == POSITION_NOT_FOUND)
    reiserfs_panic (old_dir->i_sb, "vs-7055: reiserfs_rename: new name not found");
  if (S_ISDIR(old_inode->i_mode) && reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de) == POSITION_NOT_FOUND)
    reiserfs_panic (old_dir->i_sb, "vs-7060: reiserfs_rename: \"..\" name not found");
 

  /* sanity checking before doing the rename - avoid races */
  if (!entry_points_to_object (new_dentry->d_name.name, new_dentry->d_name.len, &new_de, new_inode))
    goto try_again;
  if (!entry_points_to_object (old_dentry->d_name.name, old_dentry->d_name.len, &old_de, old_inode))
    /* go to re-looking for old entry */
    goto try_again;

  if (S_ISDIR(old_inode->i_mode) && !entry_points_to_object ("..", 2, &dot_dot_de, old_dir))
    /* go to re-looking for ".." entry of renamed directory */
    goto try_again;
  
  /* ok, all the changes can be done in one fell swoop when we have
     claimed all the buffers needed.*/

  /* make old name hidden */
  mark_de_hidden (old_de.de_deh);
  journal_mark_dirty(th, old_dir->i_sb, old_de.de_bh) ;

  /* make new name visible and set key of old object (if entry
     existed, it is already visible, if not, key is correct already) */
  mark_de_visible (new_de.de_deh);
  new_de.de_deh->deh_dir_id = INODE_PKEY (old_inode)->k_dir_id;
  new_de.de_deh->deh_objectid = INODE_PKEY (old_inode)->k_objectid;
  journal_mark_dirty(th, old_dir->i_sb, new_de.de_bh) ;

  old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  if_in_ram_update_sd (th, old_dir);

  new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
  if_in_ram_update_sd (th, new_dir);

  if (new_inode) {
    new_inode->i_nlink--;
    new_inode->i_ctime = CURRENT_TIME;
    if_in_ram_update_sd (th, new_inode);
  }
  if (dot_dot_de.de_bh) {
    set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
    journal_mark_dirty(th, old_dir->i_sb, dot_dot_de.de_bh) ;
    old_dir->i_nlink--;
    if_in_ram_update_sd (th, old_dir);
    if (new_inode) {
      new_inode->i_nlink--;
      if_in_ram_update_sd (th, new_inode);
    } else {
      new_dir->i_nlink++;
      if_in_ram_update_sd (th, new_dir);
    }
  }

  /* ok, renaming done */
  decrement_counters_in_path (&new_entry_path);
  decrement_counters_in_path (&dot_dot_entry_path);

  /* remove old name (it is hidden now) */
  if (reiserfs_cut_from_item (th, old_dir, old_dir->i_sb, &old_entry_path, &(old_de.de_entry_num),
			      &(old_de.de_entry_key), 0, PRESERVE_RENAMING) == 0)
    printk ("reiserfs_rename: could not remove old name\n");
  else {
    old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
    old_dir->i_blocks = old_dir->i_size / 512 + ((old_dir->i_size % 512) ? 1 : 0);
    if_in_ram_update_sd (th, old_dir);
  }

  /* Update the dcache */
  d_move(old_dentry, new_dentry);
  retval = 0;

end_rename:
  pathrelse (&old_entry_path);
  return retval;
}
コード例 #7
0
ファイル: namei.c プロジェクト: chinnyannieb/empeg-hijack
int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
{
  int retval;
  struct inode * inode;
  struct reiserfs_dir_entry de;
  struct path path;
  int windex ;
  int call_journal_end = 1 ;
  struct reiserfs_transaction_handle th ;
  int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 

  init_path (&path);

  retval = -ENOENT;
	
  journal_begin(&th, dir->i_sb, jbegin_count) ;
  windex = push_journal_writer("reiserfs_unlink") ;
  /* free preserve list if we should */
/*  maybe_free_preserve_list (dir->i_sb);*/
	
  de.de_gen_number_bit_string = 0;
  if (reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de) == POSITION_NOT_FOUND) {
    goto end_unlink;
  }

  inode = dentry->d_inode;

  reiserfs_update_inode_transaction(inode) ;
  reiserfs_update_inode_transaction(dir) ;

  retval = -EPERM;
  if (S_ISDIR (inode->i_mode)) {
    goto end_unlink;
  }
  if ((dir->i_mode & S_ISVTX) && !fsuser() &&
      current->fsuid != inode->i_uid &&
      current->fsuid != dir->i_uid) {
    goto end_unlink;
  }

  retval = -ENOENT;
  if (comp_short_keys ((struct key *)&(de.de_dir_id), INODE_PKEY (inode))) {
    goto end_unlink;
  }
  
  if (!inode->i_nlink) {
    printk("reiserfs_unlink: deleting nonexistent file (%s:%lu), %d\n",
	   kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
    inode->i_nlink = 1;
  }
  if (reiserfs_cut_from_item (&th, dir, dir->i_sb, &path, &(de.de_entry_num), &(de.de_entry_key), 0, NOTHING_SPECIAL) == 0) {
    retval = -ENOENT;
    goto end_unlink;
  }

  inode->i_nlink--;
  inode->i_ctime = CURRENT_TIME;
  if_in_ram_update_sd (&th, inode);

  dir->i_size -= (de.de_entrylen + DEH_SIZE);
  dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  if_in_ram_update_sd (&th, dir) ;
  pop_journal_writer(windex) ;
  journal_end(&th, dir->i_sb, jbegin_count) ;
  call_journal_end = 0 ;
  d_delete(dentry); 
  retval = 0;

end_unlink:
  pathrelse (&path);
  pop_journal_writer(windex) ;
  if (call_journal_end) 
    journal_end(&th, dir->i_sb, jbegin_count) ;
  return retval;
}
コード例 #8
0
ファイル: namei.c プロジェクト: liexusong/linux2.0-comment
/*
 * rename uses retry to avoid race-conditions: at least they should be minimal.
 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
 * checks fail, it tries to restart itself again. Very practical - no changes
 * are done until we know everything works ok.. and then all the changes can be
 * done in one fell swoop when we have claimed all the buffers needed.
 *
 * Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int do_xiafs_rename(struct inode * old_dir, const char * old_name, 
			 int old_len, struct inode * new_dir, 
			 const char * new_name, int new_len,
			 int must_be_dir)
{
    struct inode * old_inode, * new_inode;
    struct buffer_head * old_bh, * new_bh, * dir_bh;
    struct xiafs_direct * old_de, * old_de_pre, * new_de, * new_de_pre;
    int retval;

try_again:
    old_inode = new_inode = NULL;
    old_bh = new_bh = dir_bh = NULL;
    old_bh = xiafs_find_entry(old_dir, old_name, old_len, &old_de, &old_de_pre);
    retval = -ENOENT;
    if (!old_bh)
        goto end_rename;
    old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
    if (!old_inode)
        goto end_rename;
    if (must_be_dir && !S_ISDIR(old_inode->i_mode))
	goto end_rename;
    retval = -EPERM;
    if ((old_dir->i_mode & S_ISVTX) && 
	    current->fsuid != old_inode->i_uid &&
	    current->fsuid != old_dir->i_uid && !fsuser())
        goto end_rename;
    new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL);
    if (new_bh) {
        new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0);
	if (!new_inode) {
	    brelse(new_bh);
	    new_bh = NULL;
	}
    }
    if (new_inode == old_inode) {
        retval = 0;
	goto end_rename;
    }
    if (new_inode && S_ISDIR(new_inode->i_mode)) {
        retval = -EEXIST;
	goto end_rename;
    }
    retval = -EPERM;
    if (new_inode && (new_dir->i_mode & S_ISVTX) && 
	    current->fsuid != new_inode->i_uid &&
 	    current->fsuid != new_dir->i_uid && !fsuser())
        goto end_rename;
    if (S_ISDIR(old_inode->i_mode)) {
        retval = -EEXIST;
	if (new_bh)
	    goto end_rename;
	if ((retval = permission(old_inode, MAY_WRITE)) != 0)
	    goto end_rename;
	retval = -EINVAL;
	if (subdir(new_dir, old_inode))
	    goto end_rename;
	retval = -EIO;
	dir_bh = xiafs_bread(old_inode,0,0);
	if (!dir_bh)
	    goto end_rename;
	if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
	    goto end_rename;
	retval = -EMLINK;
	if (new_dir->i_nlink > 64000)
	    goto end_rename;
    }
    if (!new_bh)
        new_bh = xiafs_add_entry(new_dir, new_name, new_len, &new_de, &new_de_pre);
    retval = -ENOSPC;
    if (!new_bh) 
        goto end_rename;
    /* sanity checking */
    if ( (new_inode && (new_de->d_ino != new_inode->i_ino))
	    || (new_de->d_ino && !new_inode)
	    || (old_de->d_ino != old_inode->i_ino)) {
        xiafs_rm_entry(new_de, new_de_pre);
        brelse(old_bh);
	brelse(new_bh);
	brelse(dir_bh);
	iput(old_inode);
	iput(new_inode);
	current->counter=0;
	schedule();
	goto try_again;
    }
    xiafs_rm_entry(old_de, old_de_pre);
    new_de->d_ino = old_inode->i_ino;
    if (new_inode) {
        new_inode->i_nlink--;
	new_inode->i_dirt = 1;
    }
    mark_buffer_dirty(old_bh, 1);
    mark_buffer_dirty(new_bh, 1);
    if (dir_bh) {
        PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
	mark_buffer_dirty(dir_bh, 1);
	old_dir->i_nlink--;
	new_dir->i_nlink++;
	old_dir->i_dirt = 1;
	new_dir->i_dirt = 1;
    }
    retval = 0;
end_rename:
    brelse(dir_bh);
    brelse(old_bh);
    brelse(new_bh);
    iput(old_inode);
    iput(new_inode);
    iput(old_dir);
    iput(new_dir);
    return retval;
}
コード例 #9
0
ファイル: ioctl.c プロジェクト: rohsaini/mkunity
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
		unsigned long arg)
{
	int err;
	unsigned long flags;

	ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);

	switch (cmd) {
	case EXT2_IOC_GETFLAGS:
		err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
		if (err)
			return err;
		put_user(inode->u.ext2_i.i_flags, (int *) arg);
		return 0;
	case EXT2_IOC_SETFLAGS:
		err = verify_area(VERIFY_READ, (int *) arg, sizeof(int));
		if (err)
			return err;
		flags = get_user((int *) arg);
		/*
		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
		 * the super user when the security level is zero.
		 */
		if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^
		    (inode->u.ext2_i.i_flags &
		     (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
			/* This test looks nicer. Thanks to Pauline Middelink */
			if (!fsuser() || securelevel > 0)
				return -EPERM;
		} else
			if ((current->fsuid != inode->i_uid) && !fsuser())
				return -EPERM;
		if (IS_RDONLY(inode))
			return -EROFS;
		inode->u.ext2_i.i_flags = flags;
		if (flags & EXT2_APPEND_FL)
			inode->i_flags |= S_APPEND;
		else
			inode->i_flags &= ~S_APPEND;
		if (flags & EXT2_IMMUTABLE_FL)
			inode->i_flags |= S_IMMUTABLE;
		else
			inode->i_flags &= ~S_IMMUTABLE;
		if (flags & EXT2_NOATIME_FL)
			inode->i_flags |= MS_NOATIME;
		else
			inode->i_flags &= ~MS_NOATIME;
		inode->i_ctime = CURRENT_TIME;
		inode->i_dirt = 1;
		return 0;
	case EXT2_IOC_GETVERSION:
		err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
		if (err)
			return err;
		put_user(inode->u.ext2_i.i_version, (int *) arg);
		return 0;
	case EXT2_IOC_SETVERSION:
		if ((current->fsuid != inode->i_uid) && !fsuser())
			return -EPERM;
		if (IS_RDONLY(inode))
			return -EROFS;
		err = verify_area(VERIFY_READ, (int *) arg, sizeof(int));
		if (err)
			return err;
		inode->u.ext2_i.i_version = get_user((int *) arg);
		inode->i_ctime = CURRENT_TIME;
		inode->i_dirt = 1;
		return 0;
	default:
		return -ENOTTY;
	}
}