Exemple #1
0
static void unionfs_read_inode(struct inode *inode)
{
	static struct address_space_operations unionfs_empty_aops;

	print_entry_location();

	if (!itopd(inode)) {
		FISTBUG
		    ("No kernel memory when allocating inode private data!\n");
	}

	PASSERT(inode->i_sb);
	memset(itopd(inode), 0, sizeof(struct unionfs_inode_info));
	itopd(inode)->b_start = -1;
	itopd(inode)->b_end = -1;
	atomic_set(&itopd(inode)->uii_generation,
		   atomic_read(&stopd(inode->i_sb)->usi_generation));
	itopd(inode)->uii_rdlock = SPIN_LOCK_UNLOCKED;
	itopd(inode)->uii_rdcount = 1;
	itopd(inode)->uii_hashsize = -1;
	INIT_LIST_HEAD(&itopd(inode)->uii_readdircache);

	if (sbmax(inode->i_sb) > UNIONFS_INLINE_OBJECTS) {
		int size =
		    (sbmax(inode->i_sb) -
		     UNIONFS_INLINE_OBJECTS) * sizeof(struct inode *);
		itohi_ptr(inode) = KMALLOC(size, GFP_UNIONFS);
		if (!itohi_ptr(inode)) {
			FISTBUG
			    ("No kernel memory when allocating lower-pointer array!\n");
		}
		memset(itohi_ptr(inode), 0, size);
	}
	memset(itohi_inline(inode), 0,
	       UNIONFS_INLINE_OBJECTS * sizeof(struct inode *));

	inode->i_version++;
	inode->i_op = &unionfs_main_iops;
	inode->i_fop = &unionfs_main_fops;
	/* I don't think ->a_ops is ever allowed to be NULL */
	inode->i_mapping->a_ops = &unionfs_empty_aops;
	fist_dprint(7, "setting inode 0x%p a_ops to empty (0x%p)\n",
		    inode, inode->i_mapping->a_ops);

	print_exit_location();
}
Exemple #2
0
int copyup_named_dentry(struct inode *dir, struct dentry *dentry,
			int bstart, int new_bindex, char *name,
			int namelen, struct file **copyup_file, int len)
{
	struct dentry *new_hidden_dentry;
	struct dentry *old_hidden_dentry = NULL;
	struct super_block *sb;
	struct file *input_file = NULL;
	struct file *output_file = NULL;
	ssize_t read_bytes, write_bytes;
	mm_segment_t old_fs;
	int err = 0;
	char *buf;
	int old_bindex;
	int got_branch_input = -1;
	int got_branch_output = -1;
	int old_bstart;
	int old_bend;
	int size = len;
	struct dentry *new_hidden_parent_dentry;
	mm_segment_t oldfs;
	char *symbuf = NULL;
	uid_t saved_uid = current->fsuid;
	gid_t saved_gid = current->fsgid;

	print_entry_location();
	verify_locked(dentry);
	fist_print_dentry("IN: copyup_named_dentry", dentry);

	old_bindex = bstart;
	old_bstart = dbstart(dentry);
	old_bend = dbend(dentry);

	ASSERT(new_bindex >= 0);
	ASSERT(new_bindex < old_bindex);
	PASSERT(dir);
	PASSERT(dentry);

	sb = dir->i_sb;

	if ((err = is_robranch_super(sb, new_bindex)))
		goto out;

	/* Create the directory structure above this dentry. */
	new_hidden_dentry = create_parents_named(dir, dentry, name, new_bindex);
	PASSERT(new_hidden_dentry);
	if (IS_ERR(new_hidden_dentry)) {
		err = PTR_ERR(new_hidden_dentry);
		goto out;
	}

	fist_print_generic_dentry("Copyup Object", new_hidden_dentry);

	/* Now we actually create the object. */
	old_hidden_dentry = dtohd_index(dentry, old_bindex);
	PASSERT(old_hidden_dentry);
	PASSERT(old_hidden_dentry->d_inode);
	DGET(old_hidden_dentry);

	/* For symlinks, we must read the link before we lock the directory. */
	if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) {
		PASSERT(old_hidden_dentry->d_inode->i_op);
		PASSERT(old_hidden_dentry->d_inode->i_op->readlink);

		symbuf = KMALLOC(PATH_MAX, GFP_UNIONFS);
		if (!symbuf) {
			err = -ENOMEM;
			goto copyup_readlink_err;
		}

		oldfs = get_fs();
		set_fs(KERNEL_DS);
		err =
		    old_hidden_dentry->d_inode->i_op->
		    readlink(old_hidden_dentry, symbuf, PATH_MAX);
		set_fs(oldfs);
		if (err < 0)
			goto copyup_readlink_err;
		symbuf[err] = '\0';
	}

	/* Now we lock the parent, and create the object in the new branch. */
	new_hidden_parent_dentry = lock_parent(new_hidden_dentry);
	current->fsuid = new_hidden_parent_dentry->d_inode->i_uid;
	current->fsgid = new_hidden_parent_dentry->d_inode->i_gid;
	if (S_ISDIR(old_hidden_dentry->d_inode->i_mode)) {
		err = vfs_mkdir(new_hidden_parent_dentry->d_inode,
				new_hidden_dentry, S_IRWXU);
	} else if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		err = vfs_symlink(new_hidden_parent_dentry->d_inode,
				  new_hidden_dentry, symbuf);
#else
		err = vfs_symlink(new_hidden_parent_dentry->d_inode,
				  new_hidden_dentry, symbuf, S_IRWXU);
#endif
	} else if (S_ISBLK(old_hidden_dentry->d_inode->i_mode)
		   || S_ISCHR(old_hidden_dentry->d_inode->i_mode)
		   || S_ISFIFO(old_hidden_dentry->d_inode->i_mode)
		   || S_ISSOCK(old_hidden_dentry->d_inode->i_mode)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		err = vfs_mknod(new_hidden_parent_dentry->d_inode,
				new_hidden_dentry,
				old_hidden_dentry->d_inode->i_mode,
				kdev_t_to_nr(old_hidden_dentry->d_inode->
					     i_rdev));
#else
		err = vfs_mknod(new_hidden_parent_dentry->d_inode,
				new_hidden_dentry,
				old_hidden_dentry->d_inode->i_mode,
				old_hidden_dentry->d_inode->i_rdev);
#endif
	} else if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
		err = vfs_create(new_hidden_parent_dentry->d_inode,
				 new_hidden_dentry, S_IRWXU);
#else
		err = vfs_create(new_hidden_parent_dentry->d_inode,
				 new_hidden_dentry, S_IRWXU, NULL);
#endif
	} else {
		char diemsg[100];
		snprintf(diemsg, sizeof(diemsg), "Unknown inode type %d\n",
			 old_hidden_dentry->d_inode->i_mode);
		FISTBUG(diemsg);
	}
	current->fsuid = saved_uid;
	current->fsgid = saved_gid;
	unlock_dir(new_hidden_parent_dentry);
      copyup_readlink_err:
	KFREE(symbuf);
	if (err) {
		/* get rid of the hidden dentry and all its traces */
		DPUT(new_hidden_dentry);
		set_dtohd_index(dentry, new_bindex, NULL);
		set_dbstart(dentry, old_bstart);
		set_dbend(dentry, old_bend);
		goto out;
	}

	/* We actually copyup the file here. */
	if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) {
		mntget(stohiddenmnt_index(sb, old_bindex));
		branchget(sb, old_bindex);
		got_branch_input = old_bindex;
		input_file =
		    DENTRY_OPEN(old_hidden_dentry,
				stohiddenmnt_index(sb, old_bindex), O_RDONLY);
		if (IS_ERR(input_file)) {
			err = PTR_ERR(input_file);
			goto out;
		}
		if (!input_file->f_op || !input_file->f_op->read) {
			err = -EINVAL;
			goto out;
		}

		/* copy the new file */
		DGET(new_hidden_dentry);
		mntget(stohiddenmnt_index(sb, new_bindex));
		branchget(sb, new_bindex);
		got_branch_output = new_bindex;
		output_file =
		    DENTRY_OPEN(new_hidden_dentry,
				stohiddenmnt_index(sb, new_bindex), O_WRONLY);
		if (IS_ERR(output_file)) {
			err = PTR_ERR(output_file);
			goto out;
		}
		if (!output_file->f_op || !output_file->f_op->write) {
			err = -EINVAL;
			goto out;
		}

		/* allocating a buffer */
		buf = (char *)KMALLOC(PAGE_SIZE, GFP_UNIONFS);
		if (!buf) {
			err = -ENOMEM;
			goto out;
		}

		/* now read PAGE_SIZE bytes from offset 0 in a loop */
		old_fs = get_fs();

		input_file->f_pos = 0;
		output_file->f_pos = 0;

		set_fs(KERNEL_DS);
		do {
			if (len >= PAGE_SIZE)
				size = PAGE_SIZE;
			else if ((len < PAGE_SIZE) && (len > 0))
				size = len;

			len -= PAGE_SIZE;

			read_bytes =
			    input_file->f_op->read(input_file, buf, size,
						   &input_file->f_pos);
			if (read_bytes <= 0) {
				err = read_bytes;
				break;
			}

			write_bytes =
			    output_file->f_op->write(output_file, buf,
						     read_bytes,
						     &output_file->f_pos);
			if (write_bytes < 0 || (write_bytes < read_bytes)) {
				err = -EIO;
				break;
			}
		} while ((read_bytes > 0) && (len > 0));
		set_fs(old_fs);
		KFREE(buf);
	}

	/* Set permissions. */
	if ((err =
	     copyup_permissions(sb, old_hidden_dentry, new_hidden_dentry)))
		goto out;
	/* Selinux uses extended attributes for permissions. */
#if defined(UNIONFS_XATTR) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20))
	if ((err = copyup_xattrs(old_hidden_dentry, new_hidden_dentry)))
		goto out;
#endif

	/* do not allow files getting deleted to be reinterposed */
	if (!d_deleted(dentry))
		unionfs_reinterpose(dentry);

      out:
	if (input_file && !IS_ERR(input_file)) {
		fput(input_file);
	} else {
		/* since input file was not opened, we need to explicitly
		 * dput the old_hidden_dentry
		 */
		DPUT(old_hidden_dentry);
	}

	/* in any case, we have to branchput */
	if (got_branch_input >= 0)
		branchput(sb, got_branch_input);

	if (output_file) {
		if (copyup_file && !err) {
			*copyup_file = output_file;
		} else {
			fput(output_file);
			branchput(sb, got_branch_output);
		}
	}

	fist_print_dentry("OUT: copyup_dentry", dentry);
	fist_print_inode("OUT: copyup_dentry", dentry->d_inode);

	print_exit_status(err);
	return err;
}