Exemplo n.º 1
0
/*
 * Remount as initiated by pvfs2-client-core on restart.  This is used to
 * repopulate mount information left from previous pvfs2-client-core.
 *
 * the idea here is that given a valid superblock, we're
 * re-initializing the user space client with the initial mount
 * information specified when the super block was first initialized.
 * this is very different than the first initialization/creation of a
 * superblock.  we use the special service_priority_operation to make
 * sure that the mount gets ahead of any other pending operation that
 * is waiting for servicing.  this means that the pvfs2-client won't
 * fail to start several times for all other pending operations before
 * the client regains all of the mount information from us.
 * NOTE: this function assumes that the request_mutex is already acquired!
 */
int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
{
	struct orangefs_kernel_op_s *new_op;
	int ret = -EINVAL;

	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount: called\n");

	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
	if (!new_op)
		return -ENOMEM;
	strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
		orangefs_sb->devname,
		ORANGEFS_MAX_SERVER_ADDR_LEN);

	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "Attempting ORANGEFS Remount via host %s\n",
		     new_op->upcall.req.fs_mount.orangefs_config_server);

	/*
	 * we assume that the calling function has already acquired the
	 * request_mutex to prevent other operations from bypassing
	 * this one
	 */
	ret = service_operation(new_op, "orangefs_remount",
		ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "orangefs_remount: mount got return value of %d\n",
		     ret);
	if (ret == 0) {
		/*
		 * store the id assigned to this sb -- it's just a
		 * short-lived mapping that the system interface uses
		 * to map this superblock to a particular mount entry
		 */
		orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
		orangefs_sb->mount_pending = 0;
	}

	op_release(new_op);

	if (orangefs_userspace_version >= 20906) {
		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
		if (!new_op)
			return -ENOMEM;
		new_op->upcall.req.features.features = 0;
		ret = service_operation(new_op, "orangefs_features",
		    ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
		if (!ret)
			orangefs_features =
			    new_op->downcall.resp.features.features;
		else
			orangefs_features = 0;
		op_release(new_op);
	} else {
		orangefs_features = 0;
	}

	return ret;
}
Exemplo n.º 2
0
Arquivo: file.c Projeto: mkrufky/linux
static int flush_racache(struct inode *inode)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_kernel_op_s *new_op;
	int ret;

	gossip_debug(GOSSIP_UTILS_DEBUG,
	    "%s: %pU: Handle is %pU | fs_id %d\n", __func__,
	    get_khandle_from_ino(inode), &orangefs_inode->refn.khandle,
	    orangefs_inode->refn.fs_id);

	new_op = op_alloc(ORANGEFS_VFS_OP_RA_FLUSH);
	if (!new_op)
		return -ENOMEM;
	new_op->upcall.req.ra_cache_flush.refn = orangefs_inode->refn;

	ret = service_operation(new_op, "orangefs_flush_racache",
	    get_interruptible_flag(inode));

	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: got return value of %d\n",
	    __func__, ret);

	op_release(new_op);
	return ret;
}
Exemplo n.º 3
0
/*
 * Push all data for a specific file onto permanent storage.
 */
static int orangefs_fsync(struct file *file,
		       loff_t start,
		       loff_t end,
		       int datasync)
{
	int ret = -EINVAL;
	struct orangefs_inode_s *orangefs_inode =
		ORANGEFS_I(file->f_path.dentry->d_inode);
	struct orangefs_kernel_op_s *new_op = NULL;

	/* required call */
	filemap_write_and_wait_range(file->f_mapping, start, end);

	new_op = op_alloc(ORANGEFS_VFS_OP_FSYNC);
	if (!new_op)
		return -ENOMEM;
	new_op->upcall.req.fsync.refn = orangefs_inode->refn;

	ret = service_operation(new_op,
			"orangefs_fsync",
			get_interruptible_flag(file->f_path.dentry->d_inode));

	gossip_debug(GOSSIP_FILE_DEBUG,
		     "orangefs_fsync got return value of %d\n",
		     ret);

	op_release(new_op);

	orangefs_flush_inode(file->f_path.dentry->d_inode);
	return ret;
}
Exemplo n.º 4
0
Arquivo: file.c Projeto: mkrufky/linux
/*
 * Push all data for a specific file onto permanent storage.
 */
static int orangefs_fsync(struct file *file,
		       loff_t start,
		       loff_t end,
		       int datasync)
{
	int ret;
	struct orangefs_inode_s *orangefs_inode =
		ORANGEFS_I(file_inode(file));
	struct orangefs_kernel_op_s *new_op = NULL;

	new_op = op_alloc(ORANGEFS_VFS_OP_FSYNC);
	if (!new_op)
		return -ENOMEM;
	new_op->upcall.req.fsync.refn = orangefs_inode->refn;

	ret = service_operation(new_op,
			"orangefs_fsync",
			get_interruptible_flag(file_inode(file)));

	gossip_debug(GOSSIP_FILE_DEBUG,
		     "orangefs_fsync got return value of %d\n",
		     ret);

	op_release(new_op);

	orangefs_flush_inode(file_inode(file));
	return ret;
}
Exemplo n.º 5
0
static int orangefs_setattr_size(struct inode *inode, struct iattr *iattr)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_kernel_op_s *new_op;
	loff_t orig_size;
	int ret = -EINVAL;

	gossip_debug(GOSSIP_INODE_DEBUG,
		     "%s: %pU: Handle is %pU | fs_id %d | size is %llu\n",
		     __func__,
		     get_khandle_from_ino(inode),
		     &orangefs_inode->refn.khandle,
		     orangefs_inode->refn.fs_id,
		     iattr->ia_size);

	/* Ensure that we have a up to date size, so we know if it changed. */
	ret = orangefs_inode_getattr(inode, 0, 1);
	if (ret == -ESTALE)
		ret = -EIO;
	if (ret) {
		gossip_err("%s: orangefs_inode_getattr failed, ret:%d:.\n",
		    __func__, ret);
		return ret;
	}
	orig_size = i_size_read(inode);

	truncate_setsize(inode, iattr->ia_size);

	new_op = op_alloc(ORANGEFS_VFS_OP_TRUNCATE);
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.truncate.refn = orangefs_inode->refn;
	new_op->upcall.req.truncate.size = (__s64) iattr->ia_size;

	ret = service_operation(new_op, __func__,
				get_interruptible_flag(inode));

	/*
	 * the truncate has no downcall members to retrieve, but
	 * the status value tells us if it went through ok or not
	 */
	gossip_debug(GOSSIP_INODE_DEBUG,
		     "orangefs: orangefs_truncate got return value of %d\n",
		     ret);

	op_release(new_op);

	if (ret != 0)
		return ret;

	if (orig_size != i_size_read(inode))
		iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;

	return ret;
}
Exemplo n.º 6
0
/*
 * NOTE: information filled in here is typically reflected in the
 * output of the system command 'df'
*/
static int orangefs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	int ret = -ENOMEM;
	struct orangefs_kernel_op_s *new_op = NULL;
	int flags = 0;
	struct super_block *sb = NULL;

	sb = dentry->d_sb;

	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "orangefs_statfs: called on sb %p (fs_id is %d)\n",
		     sb,
		     (int)(ORANGEFS_SB(sb)->fs_id));

	new_op = op_alloc(ORANGEFS_VFS_OP_STATFS);
	if (!new_op)
		return ret;
	new_op->upcall.req.statfs.fs_id = ORANGEFS_SB(sb)->fs_id;

	if (ORANGEFS_SB(sb)->flags & ORANGEFS_OPT_INTR)
		flags = ORANGEFS_OP_INTERRUPTIBLE;

	ret = service_operation(new_op, "orangefs_statfs", flags);

	if (new_op->downcall.status < 0)
		goto out_op_release;

	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "%s: got %ld blocks available | "
		     "%ld blocks total | %ld block size | "
		     "%ld files total | %ld files avail\n",
		     __func__,
		     (long)new_op->downcall.resp.statfs.blocks_avail,
		     (long)new_op->downcall.resp.statfs.blocks_total,
		     (long)new_op->downcall.resp.statfs.block_size,
		     (long)new_op->downcall.resp.statfs.files_total,
		     (long)new_op->downcall.resp.statfs.files_avail);

	buf->f_type = sb->s_magic;
	memcpy(&buf->f_fsid, &ORANGEFS_SB(sb)->fs_id, sizeof(buf->f_fsid));
	buf->f_bsize = new_op->downcall.resp.statfs.block_size;
	buf->f_namelen = ORANGEFS_NAME_MAX;

	buf->f_blocks = (sector_t) new_op->downcall.resp.statfs.blocks_total;
	buf->f_bfree = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
	buf->f_bavail = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
	buf->f_files = (sector_t) new_op->downcall.resp.statfs.files_total;
	buf->f_ffree = (sector_t) new_op->downcall.resp.statfs.files_avail;
	buf->f_frsize = sb->s_blocksize;

out_op_release:
	op_release(new_op);
	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_statfs: returning %d\n", ret);
	return ret;
}
Exemplo n.º 7
0
static int orangefs_inode_removexattr(struct inode *inode,
			    const char *prefix,
			    const char *name,
			    int flags)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_kernel_op_s *new_op = NULL;
	int ret = -ENOMEM;

	down_write(&orangefs_inode->xattr_sem);
	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
	if (!new_op)
		goto out_unlock;

	new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
	/*
	 * NOTE: Although keys are meant to be NULL terminated
	 * textual strings, I am going to explicitly pass the
	 * length just in case we change this later on...
	 */
	ret = snprintf((char *)new_op->upcall.req.removexattr.key,
		       ORANGEFS_MAX_XATTR_NAMELEN,
		       "%s%s",
		       (prefix ? prefix : ""),
		       name);
	new_op->upcall.req.removexattr.key_sz = ret + 1;

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "orangefs_inode_removexattr: key %s, key_sz %d\n",
		     (char *)new_op->upcall.req.removexattr.key,
		     (int)new_op->upcall.req.removexattr.key_sz);

	ret = service_operation(new_op,
				"orangefs_inode_removexattr",
				get_interruptible_flag(inode));
	if (ret == -ENOENT) {
		/*
		 * Request to replace a non-existent attribute is an error.
		 */
		if (flags & XATTR_REPLACE)
			ret = -ENODATA;
		else
			ret = 0;
	}

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "orangefs_inode_removexattr: returning %d\n", ret);

	op_release(new_op);
out_unlock:
	up_write(&orangefs_inode->xattr_sem);
	return ret;
}
Exemplo n.º 8
0
static int orangefs_unmount(int id, __s32 fs_id, const char *devname)
{
	struct orangefs_kernel_op_s *op;
	int r;
	op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT);
	if (!op)
		return -ENOMEM;
	op->upcall.req.fs_umount.id = id;
	op->upcall.req.fs_umount.fs_id = fs_id;
	strncpy(op->upcall.req.fs_umount.orangefs_config_server,
	    devname, ORANGEFS_MAX_SERVER_ADDR_LEN - 1);
	r = service_operation(op, "orangefs_fs_umount", 0);
	/* Not much to do about an error here. */
	if (r)
		gossip_err("orangefs_unmount: service_operation %d\n", r);
	op_release(op);
	return r;
}
Exemplo n.º 9
0
void Interpreter::step()
{
	if (instruction >= file->getCodeWordCount()) return;
	
	if (system->getTick() < waitUntil)
		return;
	
	const uint16_t *code = file->getCode();
	
	if (code[instruction] & (1 << 11))
	{
		// Short format	
		unsigned opcode = (code[instruction] & 0x0700) >> 8;
		int argDiff = (int8_t) (code[instruction] & 0xFF);
		uint16_t arguments[2];
		switch(opcode)
		{
			case 0: // SHORT_OP_MOV
				arguments[0] = argDiff + code[instruction + 1];
				arguments[1] = code[instruction + 1];
				instruction += 2;
				op_mov(0, arguments);
				break;
			case 1: // SHORT_OP_ACQUIRE
				arguments[0] = argDiff;
				instruction += 1;
				op_acquire(0, arguments);
				break;
			case 2: // SHORT_OP_RELEASE
				arguments[0] = argDiff;
				instruction += 1;
				op_release(0, arguments);
				break;
			case 3: // SHORT_OP_SUBCALL
				arguments[0] = argDiff + code[instruction + 1]; // Subroutine
				arguments[1] = code[instruction + 1]; // Caller ID
				instruction += 2; // Instruction has to be on the next before
				// branching to subroutine so it can be used as return inst.
				op_subcall(0, arguments);
				break;
			default:
				throw std::runtime_error("Invalid short opcode.");
		}		
	}
Exemplo n.º 10
0
/* return 0 on success; non-zero otherwise */
static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: called on %s\n"
		     "  (inode %pU): Parent is %pU | fs_id %d\n",
		     __func__,
		     dentry->d_name.name,
		     get_khandle_from_ino(inode),
		     &parent->refn.khandle,
		     parent->refn.fs_id);

	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.remove.parent_refn = parent->refn;
	strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name,
		ORANGEFS_NAME_MAX);

	ret = service_operation(new_op, "orangefs_unlink",
				get_interruptible_flag(inode));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: service_operation returned:%d:\n",
		     __func__,
		     ret);

	op_release(new_op);

	if (!ret) {
		drop_nlink(inode);

		SetMtimeFlag(parent);
		dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
		mark_inode_dirty_sync(dir);
	}
	return ret;
}
Exemplo n.º 11
0
static int orangefs_rename(struct inode *old_dir,
			struct dentry *old_dentry,
			struct inode *new_dir,
			struct dentry *new_dentry)
{
	struct orangefs_kernel_op_s *new_op;
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
		     old_dentry, new_dentry, d_count(new_dentry));

	ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1;

	new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
	if (!new_op)
		return -EINVAL;

	new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
	new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;

	strncpy(new_op->upcall.req.rename.d_old_name,
		old_dentry->d_name.name,
		ORANGEFS_NAME_MAX);
	strncpy(new_op->upcall.req.rename.d_new_name,
		new_dentry->d_name.name,
		ORANGEFS_NAME_MAX);

	ret = service_operation(new_op,
				"orangefs_rename",
				get_interruptible_flag(old_dentry->d_inode));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "orangefs_rename: got downcall status %d\n",
		     ret);

	if (new_dentry->d_inode)
		new_dentry->d_inode->i_ctime = CURRENT_TIME;

	op_release(new_op);
	return ret;
}
Exemplo n.º 12
0
/*
 * Attempt to resolve an object name (dentry->d_name), parent handle, and
 * fsid into a handle for the object.
 */
static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
				   unsigned int flags)
{
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
	struct inode *inode;
	struct dentry *res;
	int ret = -EINVAL;

	/*
	 * in theory we could skip a lookup here (if the intent is to
	 * create) in order to avoid a potentially failed lookup, but
	 * leaving it in can skip a valid lookup and try to create a file
	 * that already exists (e.g. the vfs already handles checking for
	 * -EEXIST on O_EXCL opens, which is broken if we skip this lookup
	 * in the create path)
	 */
	gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %s\n",
		     __func__, dentry->d_name.name);

	if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
		return ERR_PTR(-ENAMETOOLONG);

	new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
	if (!new_op)
		return ERR_PTR(-ENOMEM);

	new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;

	gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n",
		     __FILE__,
		     __func__,
		     __LINE__,
		     &parent->refn.khandle);
	new_op->upcall.req.lookup.parent_refn = parent->refn;

	strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name,
		ORANGEFS_NAME_MAX);

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: doing lookup on %s under %pU,%d\n",
		     __func__,
		     new_op->upcall.req.lookup.d_name,
		     &new_op->upcall.req.lookup.parent_refn.khandle,
		     new_op->upcall.req.lookup.parent_refn.fs_id);

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Lookup Got %pU, fsid %d (ret=%d)\n",
		     &new_op->downcall.resp.lookup.refn.khandle,
		     new_op->downcall.resp.lookup.refn.fs_id,
		     ret);

	if (ret < 0) {
		if (ret == -ENOENT) {
			/*
			 * if no inode was found, add a negative dentry to
			 * dcache anyway; if we don't, we don't hold expected
			 * lookup semantics and we most noticeably break
			 * during directory renames.
			 *
			 * however, if the operation failed or exited, do not
			 * add the dentry (e.g. in the case that a touch is
			 * issued on a file that already exists that was
			 * interrupted during this lookup -- no need to add
			 * another negative dentry for an existing file)
			 */

			gossip_debug(GOSSIP_NAME_DEBUG,
				     "orangefs_lookup: Adding *negative* dentry "
				     "%p for %s\n",
				     dentry,
				     dentry->d_name.name);

			d_add(dentry, NULL);
			res = NULL;
			goto out;
		}

		/* must be a non-recoverable error */
		res = ERR_PTR(ret);
		goto out;
	}

	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;

	inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
	if (IS_ERR(inode)) {
		gossip_debug(GOSSIP_NAME_DEBUG,
			"error %ld from iget\n", PTR_ERR(inode));
		res = ERR_CAST(inode);
		goto out;
	}

	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s:%s:%d "
		     "Found good inode [%lu] with count [%d]\n",
		     __FILE__,
		     __func__,
		     __LINE__,
		     inode->i_ino,
		     (int)atomic_read(&inode->i_count));

	/* update dentry/inode pair into dcache */
	res = d_splice_alias(inode, dentry);

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Lookup success (inode ct = %d)\n",
		     (int)atomic_read(&inode->i_count));
out:
	op_release(new_op);
	return res;
}
Exemplo n.º 13
0
/*
 * Get a newly allocated inode to go with a negative dentry.
 */
static int orangefs_create(struct inode *dir,
			struct dentry *dentry,
			umode_t mode,
			bool exclusive)
{
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
	struct inode *inode;
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG, "%s: %s\n",
		     __func__,
		     dentry->d_name.name);

	new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.create.parent_refn = parent->refn;

	fill_default_sys_attrs(new_op->upcall.req.create.attributes,
			       ORANGEFS_TYPE_METAFILE, mode);

	strncpy(new_op->upcall.req.create.d_name,
		dentry->d_name.name, ORANGEFS_NAME_MAX);

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: %s: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
		     __func__,
		     dentry->d_name.name,
		     &new_op->downcall.resp.create.refn.khandle,
		     new_op->downcall.resp.create.refn.fs_id,
		     new_op,
		     ret);

	if (ret < 0)
		goto out;

	inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0,
				&new_op->downcall.resp.create.refn);
	if (IS_ERR(inode)) {
		gossip_err("%s: Failed to allocate inode for file :%s:\n",
			   __func__,
			   dentry->d_name.name);
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: Assigned inode :%pU: for file :%s:\n",
		     __func__,
		     get_khandle_from_ino(inode),
		     dentry->d_name.name);

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: dentry instantiated for %s\n",
		     __func__,
		     dentry->d_name.name);

	SetMtimeFlag(parent);
	dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
	mark_inode_dirty_sync(dir);
	ret = 0;
out:
	op_release(new_op);
	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: %s: returning %d\n",
		     __func__,
		     dentry->d_name.name,
		     ret);
	return ret;
}
Exemplo n.º 14
0
/*
 * Post and wait for the I/O upcall to finish
 */
static ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inode,
		loff_t *offset, struct iov_iter *iter,
		size_t total_size, loff_t readahead_size)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_khandle *handle = &orangefs_inode->refn.khandle;
	struct orangefs_kernel_op_s *new_op = NULL;
	struct iov_iter saved = *iter;
	int buffer_index = -1;
	ssize_t ret;

	new_op = op_alloc(ORANGEFS_VFS_OP_FILE_IO);
	if (!new_op)
		return -ENOMEM;

	/* synchronous I/O */
	new_op->upcall.req.io.readahead_size = readahead_size;
	new_op->upcall.req.io.io_type = type;
	new_op->upcall.req.io.refn = orangefs_inode->refn;

populate_shared_memory:
	/* get a shared buffer index */
	buffer_index = orangefs_bufmap_get();
	if (buffer_index < 0) {
		ret = buffer_index;
		gossip_debug(GOSSIP_FILE_DEBUG,
			     "%s: orangefs_bufmap_get failure (%zd)\n",
			     __func__, ret);
		goto out;
	}
	gossip_debug(GOSSIP_FILE_DEBUG,
		     "%s(%pU): GET op %p -> buffer_index %d\n",
		     __func__,
		     handle,
		     new_op,
		     buffer_index);

	new_op->uses_shared_memory = 1;
	new_op->upcall.req.io.buf_index = buffer_index;
	new_op->upcall.req.io.count = total_size;
	new_op->upcall.req.io.offset = *offset;

	gossip_debug(GOSSIP_FILE_DEBUG,
		     "%s(%pU): offset: %llu total_size: %zd\n",
		     __func__,
		     handle,
		     llu(*offset),
		     total_size);
	/*
	 * Stage 1: copy the buffers into client-core's address space
	 * precopy_buffers only pertains to writes.
	 */
	if (type == ORANGEFS_IO_WRITE) {
		ret = precopy_buffers(buffer_index,
				      iter,
				      total_size);
		if (ret < 0)
			goto out;
	}

	gossip_debug(GOSSIP_FILE_DEBUG,
		     "%s(%pU): Calling post_io_request with tag (%llu)\n",
		     __func__,
		     handle,
		     llu(new_op->tag));

	/* Stage 2: Service the I/O operation */
	ret = service_operation(new_op,
				type == ORANGEFS_IO_WRITE ?
					"file_write" :
					"file_read",
				get_interruptible_flag(inode));

	/*
	 * If service_operation() returns -EAGAIN #and# the operation was
	 * purged from orangefs_request_list or htable_ops_in_progress, then
	 * we know that the client was restarted, causing the shared memory
	 * area to be wiped clean.  To restart a  write operation in this
	 * case, we must re-copy the data from the user's iovec to a NEW
	 * shared memory location. To restart a read operation, we must get
	 * a new shared memory location.
	 */
	if (ret == -EAGAIN && op_state_purged(new_op)) {
		orangefs_bufmap_put(buffer_index);
		buffer_index = -1;
		if (type == ORANGEFS_IO_WRITE)
			*iter = saved;
		gossip_debug(GOSSIP_FILE_DEBUG,
			     "%s:going to repopulate_shared_memory.\n",
			     __func__);
		goto populate_shared_memory;
	}

	if (ret < 0) {
		if (ret == -EINTR) {
			/*
			 * We can't return EINTR if any data was written,
			 * it's not POSIX. It is minimally acceptable
			 * to give a partial write, the way NFS does.
			 *
			 * It would be optimal to return all or nothing,
			 * but if a userspace write is bigger than
			 * an IO buffer, and the interrupt occurs
			 * between buffer writes, that would not be
			 * possible.
			 */
			switch (new_op->op_state - OP_VFS_STATE_GIVEN_UP) {
			/*
			 * If the op was waiting when the interrupt
			 * occurred, then the client-core did not
			 * trigger the write.
			 */
			case OP_VFS_STATE_WAITING:
				if (*offset == 0)
					ret = -EINTR;
				else
					ret = 0;
				break;
			/* 
			 * If the op was in progress when the interrupt
			 * occurred, then the client-core was able to
			 * trigger the write.
			 */
			case OP_VFS_STATE_INPROGR:
				ret = total_size;
				break;
			default:
				gossip_err("%s: unexpected op state :%d:.\n",
					   __func__,
					   new_op->op_state);
				ret = 0;
				break;
			}
			gossip_debug(GOSSIP_FILE_DEBUG,
				     "%s: got EINTR, state:%d: %p\n",
				     __func__,
				     new_op->op_state,
				     new_op);
		} else {
			gossip_err("%s: error in %s handle %pU, returning %zd\n",
				__func__,
				type == ORANGEFS_IO_READ ?
					"read from" : "write to",
				handle, ret);
		}
		if (orangefs_cancel_op_in_progress(new_op))
			return ret;

		goto out;
	}

	/*
	 * Stage 3: Post copy buffers from client-core's address space
	 * postcopy_buffers only pertains to reads.
	 */
	if (type == ORANGEFS_IO_READ) {
		ret = postcopy_buffers(buffer_index,
				       iter,
				       new_op->downcall.resp.io.amt_complete);
		if (ret < 0)
			goto out;
	}
	gossip_debug(GOSSIP_FILE_DEBUG,
	    "%s(%pU): Amount %s, returned by the sys-io call:%d\n",
	    __func__,
	    handle,
	    type == ORANGEFS_IO_READ ?  "read" : "written",
	    (int)new_op->downcall.resp.io.amt_complete);

	ret = new_op->downcall.resp.io.amt_complete;

out:
	if (buffer_index >= 0) {
		orangefs_bufmap_put(buffer_index);
		gossip_debug(GOSSIP_FILE_DEBUG,
			     "%s(%pU): PUT buffer_index %d\n",
			     __func__, handle, buffer_index);
		buffer_index = -1;
	}
	op_release(new_op);
	return ret;
}
Exemplo n.º 15
0
struct dentry *orangefs_mount(struct file_system_type *fst,
			   int flags,
			   const char *devname,
			   void *data)
{
	int ret = -EINVAL;
	struct super_block *sb = ERR_PTR(-EINVAL);
	struct orangefs_kernel_op_s *new_op;
	struct dentry *d = ERR_PTR(-EINVAL);

	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "orangefs_mount: called with devname %s\n",
		     devname);

	if (!devname) {
		gossip_err("ERROR: device name not specified.\n");
		return ERR_PTR(-EINVAL);
	}

	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
	if (!new_op)
		return ERR_PTR(-ENOMEM);

	strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
		devname,
		ORANGEFS_MAX_SERVER_ADDR_LEN - 1);

	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "Attempting ORANGEFS Mount via host %s\n",
		     new_op->upcall.req.fs_mount.orangefs_config_server);

	ret = service_operation(new_op, "orangefs_mount", 0);
	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "orangefs_mount: mount got return value of %d\n", ret);
	if (ret)
		goto free_op;

	if (new_op->downcall.resp.fs_mount.fs_id == ORANGEFS_FS_ID_NULL) {
		gossip_err("ERROR: Retrieved null fs_id\n");
		ret = -EINVAL;
		goto free_op;
	}

	sb = sget(fst, NULL, set_anon_super, flags, NULL);

	if (IS_ERR(sb)) {
		d = ERR_CAST(sb);
		orangefs_unmount(new_op->downcall.resp.fs_mount.id,
		    new_op->downcall.resp.fs_mount.fs_id, devname);
		goto free_op;
	}

	ret = orangefs_fill_sb(sb,
	      &new_op->downcall.resp.fs_mount, data,
	      flags & SB_SILENT ? 1 : 0);

	if (ret) {
		d = ERR_PTR(ret);
		goto free_sb_and_op;
	}

	/*
	 * on successful mount, store the devname and data
	 * used
	 */
	strncpy(ORANGEFS_SB(sb)->devname,
		devname,
		ORANGEFS_MAX_SERVER_ADDR_LEN - 1);

	/* mount_pending must be cleared */
	ORANGEFS_SB(sb)->mount_pending = 0;

	/*
	 * finally, add this sb to our list of known orangefs
	 * sb's
	 */
	gossip_debug(GOSSIP_SUPER_DEBUG,
		     "Adding SB %p to orangefs superblocks\n",
		     ORANGEFS_SB(sb));
	spin_lock(&orangefs_superblocks_lock);
	list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks);
	spin_unlock(&orangefs_superblocks_lock);
	op_release(new_op);

	/* Must be removed from the list now. */
	ORANGEFS_SB(sb)->no_list = 0;

	if (orangefs_userspace_version >= 20906) {
		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
		if (!new_op)
			return ERR_PTR(-ENOMEM);
		new_op->upcall.req.features.features = 0;
		ret = service_operation(new_op, "orangefs_features", 0);
		orangefs_features = new_op->downcall.resp.features.features;
		op_release(new_op);
	} else {
		orangefs_features = 0;
	}

	return dget(sb->s_root);

free_sb_and_op:
	/* Will call orangefs_kill_sb with sb not in list. */
	ORANGEFS_SB(sb)->no_list = 1;
	/* ORANGEFS_VFS_OP_FS_UMOUNT is done by orangefs_kill_sb. */
	deactivate_locked_super(sb);
free_op:
	gossip_err("orangefs_mount: mount request failed with %d\n", ret);
	if (ret == -EINVAL) {
		gossip_err("Ensure that all orangefs-servers have the same FS configuration files\n");
		gossip_err("Look at pvfs2-client-core log file (typically /tmp/pvfs2-client.log) for more details\n");
	}

	op_release(new_op);

	return d;
}
Exemplo n.º 16
0
static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
	struct inode *inode;
	int ret;

	new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.mkdir.parent_refn = parent->refn;

	fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
			      ORANGEFS_TYPE_DIRECTORY, mode);

	strncpy(new_op->upcall.req.mkdir.d_name,
		dentry->d_name.name, ORANGEFS_NAME_MAX);

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
		     &new_op->downcall.resp.mkdir.refn.khandle,
		     new_op->downcall.resp.mkdir.refn.fs_id);

	if (ret < 0) {
		gossip_debug(GOSSIP_NAME_DEBUG,
			     "%s: failed with error code %d\n",
			     __func__, ret);
		goto out;
	}

	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
				&new_op->downcall.resp.mkdir.refn);
	if (IS_ERR(inode)) {
		gossip_err("*** Failed to allocate orangefs dir inode\n");
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Assigned dir inode new number of %pU\n",
		     get_khandle_from_ino(inode));

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Inode (Directory) %pU -> %s\n",
		     get_khandle_from_ino(inode),
		     dentry->d_name.name);

	/*
	 * NOTE: we have no good way to keep nlink consistent for directories
	 * across clients; keep constant at 1.
	 */
	SetMtimeFlag(parent);
	dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
	mark_inode_dirty_sync(dir);
out:
	op_release(new_op);
	return ret;
}
Exemplo n.º 17
0
/*
 * Tries to get a specified key's attributes of a given
 * file into a user-specified buffer. Note that the getxattr
 * interface allows for the users to probe the size of an
 * extended attribute by passing in a value of 0 to size.
 * Thus our return value is always the size of the attribute
 * unless the key does not exist for the file and/or if
 * there were errors in fetching the attribute value.
 */
ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
				void *buffer, size_t size)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_kernel_op_s *new_op = NULL;
	ssize_t ret = -ENOMEM;
	ssize_t length = 0;
	int fsuid;
	int fsgid;

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "%s: name %s, buffer_size %zd\n",
		     __func__, name, size);

	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;

	if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
		return -EINVAL;

	fsuid = from_kuid(&init_user_ns, current_fsuid());
	fsgid = from_kgid(&init_user_ns, current_fsgid());

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "getxattr on inode %pU, name %s "
		     "(uid %o, gid %o)\n",
		     get_khandle_from_ino(inode),
		     name,
		     fsuid,
		     fsgid);

	down_read(&orangefs_inode->xattr_sem);

	new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
	if (!new_op)
		goto out_unlock;

	new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
	strcpy(new_op->upcall.req.getxattr.key, name);

	/*
	 * NOTE: Although keys are meant to be NULL terminated textual
	 * strings, I am going to explicitly pass the length just in case
	 * we change this later on...
	 */
	new_op->upcall.req.getxattr.key_sz = strlen(name) + 1;

	ret = service_operation(new_op, "orangefs_inode_getxattr",
				get_interruptible_flag(inode));
	if (ret != 0) {
		if (ret == -ENOENT) {
			ret = -ENODATA;
			gossip_debug(GOSSIP_XATTR_DEBUG,
				     "orangefs_inode_getxattr: inode %pU key %s"
				     " does not exist!\n",
				     get_khandle_from_ino(inode),
				     (char *)new_op->upcall.req.getxattr.key);
		}
		goto out_release_op;
	}

	/*
	 * Length returned includes null terminator.
	 */
	length = new_op->downcall.resp.getxattr.val_sz;

	/*
	 * Just return the length of the queried attribute.
	 */
	if (size == 0) {
		ret = length;
		goto out_release_op;
	}

	/*
	 * Check to see if key length is > provided buffer size.
	 */
	if (length > size) {
		ret = -ERANGE;
		goto out_release_op;
	}

	memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
	memset(buffer + length, 0, size - length);
	gossip_debug(GOSSIP_XATTR_DEBUG,
	     "orangefs_inode_getxattr: inode %pU "
	     "key %s key_sz %d, val_len %d\n",
	     get_khandle_from_ino(inode),
	     (char *)new_op->
		upcall.req.getxattr.key,
		     (int)new_op->
		upcall.req.getxattr.key_sz,
	     (int)ret);

	ret = length;

out_release_op:
	op_release(new_op);
out_unlock:
	up_read(&orangefs_inode->xattr_sem);
	return ret;
}
Exemplo n.º 18
0
Arquivo: namei.c Projeto: Goon83/SALB
static struct dentry *pvfs2_lookup(
    struct inode *dir,
    struct dentry *dentry,
    struct nameidata *nd)
#endif
{
    int ret = -EINVAL;
    struct inode *inode = NULL;
    pvfs2_kernel_op_t *new_op = NULL;
    pvfs2_inode_t *parent = NULL, *found_pvfs2_inode = NULL;
    struct super_block *sb = NULL;

    /*
      in theory we could skip a lookup here (if the intent is to
      create) in order to avoid a potentially failed lookup, but
      leaving it in can skip a valid lookup and try to create a file
      that already exists (e.g. the vfs already handles checking for
      -EEXIST on O_EXCL opens, which is broken if we skip this lookup
      in the create path)
    */
    gossip_debug(GOSSIP_NAME_DEBUG, "pvfs2_lookup called on %s\n", dentry->d_name.name);

    if (dentry->d_name.len > (PVFS2_NAME_LEN-1))
    {
	return ERR_PTR(-ENAMETOOLONG);
    }

    new_op = op_alloc(PVFS2_VFS_OP_LOOKUP);
    if (!new_op)
    {
	return ERR_PTR(-ENOMEM);
    }

#ifdef PVFS2_LINUX_KERNEL_2_4
    new_op->upcall.req.lookup.sym_follow = PVFS2_LOOKUP_LINK_NO_FOLLOW;
#else
    /*
      if we're at a symlink, should we follow it? never attempt to
      follow negative dentries
    */
    new_op->upcall.req.lookup.sym_follow =
        ((nd && (nd->flags & LOOKUP_FOLLOW) &&
          (dentry->d_inode != NULL)) ?
         PVFS2_LOOKUP_LINK_FOLLOW : PVFS2_LOOKUP_LINK_NO_FOLLOW);
#endif

    if (dir)
    {
        sb = dir->i_sb;
        parent = PVFS2_I(dir);
        if (parent && parent->refn.handle != PVFS_HANDLE_NULL 
                && parent->refn.fs_id != PVFS_FS_ID_NULL)
        {
            gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %llu\n",
              __FILE__, __func__, __LINE__, llu(parent->refn.handle));
            new_op->upcall.req.lookup.parent_refn = parent->refn;
        }
        else
        {
#if defined(HAVE_IGET4_LOCKED) || defined(HAVE_IGET5_LOCKED)
            gossip_lerr("Critical error: i_ino cannot be relied on when using iget5/iget4\n");
            op_release(new_op);
            return ERR_PTR(-EINVAL);
#endif
            new_op->upcall.req.lookup.parent_refn.handle =
                get_handle_from_ino(dir);
            new_op->upcall.req.lookup.parent_refn.fs_id =
                PVFS2_SB(sb)->fs_id;
        }
    }
    else
    {
        /*
          if no parent at all was provided, use the root
          handle and file system id stored in the super
          block for the specified dentry's inode
        */
        sb = dentry->d_inode->i_sb;
	new_op->upcall.req.lookup.parent_refn.handle =
	    PVFS2_SB(sb)->root_handle;
	new_op->upcall.req.lookup.parent_refn.fs_id =
	    PVFS2_SB(sb)->fs_id;
    }
    strncpy(new_op->upcall.req.lookup.d_name,
	    dentry->d_name.name, PVFS2_NAME_LEN);

    gossip_debug(GOSSIP_NAME_DEBUG, "pvfs2_lookup: doing lookup on %s\n  under %llu,%d "
                "(follow=%s)\n", new_op->upcall.req.lookup.d_name,
                llu(new_op->upcall.req.lookup.parent_refn.handle),
                new_op->upcall.req.lookup.parent_refn.fs_id,
                ((new_op->upcall.req.lookup.sym_follow ==
                  PVFS2_LOOKUP_LINK_FOLLOW) ? "yes" : "no"));

    ret = service_operation(
        new_op, "pvfs2_lookup", 
        get_interruptible_flag(dir));

    gossip_debug(GOSSIP_NAME_DEBUG, "Lookup Got %llu, fsid %d (ret=%d)\n",
                llu(new_op->downcall.resp.lookup.refn.handle),
                new_op->downcall.resp.lookup.refn.fs_id, ret);

    if(ret < 0)
    {
        if(ret == -ENOENT)
        {
            /*
             * if no inode was found, add a negative dentry to dcache anyway;
             * if we don't, we don't hold expected lookup semantics and we most
             * noticeably break during directory renames.
             *
             * however, if the operation failed or exited, do not add the
             * dentry (e.g. in the case that a touch is issued on a file that
             * already exists that was interrupted during this lookup -- no
             * need to add another negative dentry for an existing file)
             */

            gossip_debug(GOSSIP_NAME_DEBUG, 
                         "pvfs2_lookup: Adding *negative* dentry %p\n for %s\n",
                         dentry, dentry->d_name.name);

            /*
             * make sure to set the pvfs2 specific dentry operations for
             * the negative dentry that we're adding now so that a
             * potential future lookup of this cached negative dentry can
             * be properly revalidated.
             */
            dentry->d_op = &pvfs2_dentry_operations;
            d_add(dentry, inode);

            op_release(new_op);
            return NULL;
        }

        op_release(new_op);
        /* must be a non-recoverable error */
        return ERR_PTR(ret);
    }

    inode = pvfs2_iget(sb, &new_op->downcall.resp.lookup.refn);
    if (inode && !is_bad_inode(inode))
    {
        struct dentry *res;

        gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d Found good inode [%lu] with count [%d]\n", 
            __FILE__, __func__, __LINE__, inode->i_ino, (int)atomic_read(&inode->i_count));

        /* update dentry/inode pair into dcache */
        dentry->d_op = &pvfs2_dentry_operations;

        res = pvfs2_d_splice_alias(dentry, inode);

        gossip_debug(GOSSIP_NAME_DEBUG, "Lookup success (inode ct = %d)\n",
                     (int)atomic_read(&inode->i_count));
        if (res)
            res->d_op = &pvfs2_dentry_operations;

        op_release(new_op);
#ifdef PVFS2_LINUX_KERNEL_2_4
        return NULL;
#else
        return res;
#endif
    }
    else if (inode && is_bad_inode(inode))
    {
        gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d Found bad inode [%lu] with count [%d]. Returning error [%d]", 
            __FILE__, __func__, __LINE__, inode->i_ino, (int)atomic_read(&inode->i_count), ret);
        ret = -EACCES;
        found_pvfs2_inode = PVFS2_I(inode);
        /* look for an error code, possibly set by pvfs2_read_inode(),
         * otherwise we have to guess EACCES 
         */
        if(found_pvfs2_inode->error_code)
        {
            ret = found_pvfs2_inode->error_code;
        }
        iput(inode);
        op_release(new_op);
        return ERR_PTR(ret);
    }

    /* no error was returned from service_operation, but the inode
     * from pvfs2_iget was null...just return EACCESS
     */
    op_release(new_op);
    gossip_debug(GOSSIP_NAME_DEBUG, "Returning -EACCES for NULL inode\n");
    return ERR_PTR(-EACCES);
}
Exemplo n.º 19
0
static int orangefs_symlink(struct inode *dir,
			 struct dentry *dentry,
			 const char *symname)
{
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
	struct inode *inode;
	int mode = 755;
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__);

	if (!symname)
		return -EINVAL;

	if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
		return -ENAMETOOLONG;

	new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.sym.parent_refn = parent->refn;

	fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
			       ORANGEFS_TYPE_SYMLINK,
			       mode);

	strncpy(new_op->upcall.req.sym.entry_name,
		dentry->d_name.name,
		ORANGEFS_NAME_MAX);
	strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX);

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
		     &new_op->downcall.resp.sym.refn.khandle,
		     new_op->downcall.resp.sym.refn.fs_id, ret);

	if (ret < 0) {
		gossip_debug(GOSSIP_NAME_DEBUG,
			    "%s: failed with error code %d\n",
			    __func__, ret);
		goto out;
	}

	inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
				&new_op->downcall.resp.sym.refn);
	if (IS_ERR(inode)) {
		gossip_err
		    ("*** Failed to allocate orangefs symlink inode\n");
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Assigned symlink inode new number of %pU\n",
		     get_khandle_from_ino(inode));

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Inode (Symlink) %pU -> %s\n",
		     get_khandle_from_ino(inode),
		     dentry->d_name.name);

	SetMtimeFlag(parent);
	dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
	mark_inode_dirty_sync(dir);
	ret = 0;
out:
	op_release(new_op);
	return ret;
}
Exemplo n.º 20
0
/*
 * Tries to set an attribute for a given key on a file.
 *
 * Returns a -ve number on error and 0 on success.  Key is text, but value
 * can be binary!
 */
int orangefs_inode_setxattr(struct inode *inode, const char *name,
			    const void *value, size_t size, int flags)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_kernel_op_s *new_op;
	int internal_flag = 0;
	int ret = -ENOMEM;

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "%s: name %s, buffer_size %zd\n",
		     __func__, name, size);

	if (size > ORANGEFS_MAX_XATTR_VALUELEN)
		return -EINVAL;
	if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
		return -EINVAL;

	internal_flag = convert_to_internal_xattr_flags(flags);

	/* This is equivalent to a removexattr */
	if (size == 0 && !value) {
		gossip_debug(GOSSIP_XATTR_DEBUG,
			     "removing xattr (%s)\n",
			     name);
		return orangefs_inode_removexattr(inode, name, flags);
	}

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "setxattr on inode %pU, name %s\n",
		     get_khandle_from_ino(inode),
		     name);

	down_write(&orangefs_inode->xattr_sem);
	new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
	if (!new_op)
		goto out_unlock;


	new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
	new_op->upcall.req.setxattr.flags = internal_flag;
	/*
	 * NOTE: Although keys are meant to be NULL terminated textual
	 * strings, I am going to explicitly pass the length just in
	 * case we change this later on...
	 */
	strcpy(new_op->upcall.req.setxattr.keyval.key, name);
	new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1;
	memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
	new_op->upcall.req.setxattr.keyval.val_sz = size;

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "orangefs_inode_setxattr: key %s, key_sz %d "
		     " value size %zd\n",
		     (char *)new_op->upcall.req.setxattr.keyval.key,
		     (int)new_op->upcall.req.setxattr.keyval.key_sz,
		     size);

	ret = service_operation(new_op,
				"orangefs_inode_setxattr",
				get_interruptible_flag(inode));

	gossip_debug(GOSSIP_XATTR_DEBUG,
		     "orangefs_inode_setxattr: returning %d\n",
		     ret);

	/* when request is serviced properly, free req op struct */
	op_release(new_op);
out_unlock:
	up_write(&orangefs_inode->xattr_sem);
	return ret;
}
Exemplo n.º 21
0
/*
 * Tries to get a specified object's keys into a user-specified buffer of a
 * given size.  Note that like the previous instances of xattr routines, this
 * also allows you to pass in a NULL pointer and 0 size to probe the size for
 * subsequent memory allocations. Thus our return value is always the size of
 * all the keys unless there were errors in fetching the keys!
 */
ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
	struct inode *inode = dentry->d_inode;
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct orangefs_kernel_op_s *new_op;
	__u64 token = ORANGEFS_ITERATE_START;
	ssize_t ret = -ENOMEM;
	ssize_t total = 0;
	int count_keys = 0;
	int key_size;
	int i = 0;
	int returned_count = 0;

	if (size > 0 && !buffer) {
		gossip_err("%s: bogus NULL pointers\n", __func__);
		return -EINVAL;
	}

	down_read(&orangefs_inode->xattr_sem);
	new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
	if (!new_op)
		goto out_unlock;

	if (buffer && size > 0)
		memset(buffer, 0, size);

try_again:
	key_size = 0;
	new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
	new_op->upcall.req.listxattr.token = token;
	new_op->upcall.req.listxattr.requested_count =
	    (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
	ret = service_operation(new_op, __func__,
				get_interruptible_flag(inode));
	if (ret != 0)
		goto done;

	if (size == 0) {
		/*
		 * This is a bit of a big upper limit, but I did not want to
		 * spend too much time getting this correct, since users end
		 * up allocating memory rather than us...
		 */
		total = new_op->downcall.resp.listxattr.returned_count *
			ORANGEFS_MAX_XATTR_NAMELEN;
		goto done;
	}

	returned_count = new_op->downcall.resp.listxattr.returned_count;
	if (returned_count < 0 ||
	    returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
		gossip_err("%s: impossible value for returned_count:%d:\n",
		__func__,
		returned_count);
		ret = -EIO;
		goto done;
	}

	/*
	 * Check to see how much can be fit in the buffer. Fit only whole keys.
	 */
	for (i = 0; i < returned_count; i++) {
		if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
		    new_op->downcall.resp.listxattr.lengths[i] >
		    ORANGEFS_MAX_XATTR_NAMELEN) {
			gossip_err("%s: impossible value for lengths[%d]\n",
			    __func__,
			    new_op->downcall.resp.listxattr.lengths[i]);
			ret = -EIO;
			goto done;
		}
		if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
			goto done;

		/*
		 * Since many dumb programs try to setxattr() on our reserved
		 * xattrs this is a feeble attempt at defeating those by not
		 * listing them in the output of listxattr.. sigh
		 */
		if (is_reserved_key(new_op->downcall.resp.listxattr.key +
				    key_size,
				    new_op->downcall.resp.
					listxattr.lengths[i])) {
			gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
					i, new_op->downcall.resp.listxattr.key +
						key_size);
			memcpy(buffer + total,
				new_op->downcall.resp.listxattr.key + key_size,
				new_op->downcall.resp.listxattr.lengths[i]);
			total += new_op->downcall.resp.listxattr.lengths[i];
			count_keys++;
		} else {
			gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
					i, new_op->downcall.resp.listxattr.key +
						key_size);
		}
		key_size += new_op->downcall.resp.listxattr.lengths[i];
	}

	/*
	 * Since the buffer was large enough, we might have to continue
	 * fetching more keys!
	 */
	token = new_op->downcall.resp.listxattr.token;
	if (token != ORANGEFS_ITERATE_END)
		goto try_again;

done:
	gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
		     " [size of buffer %ld] (filled in %d keys)\n",
		     __func__,
		     ret ? (int)ret : (int)total,
		     (long)size,
		     count_keys);
	op_release(new_op);
	if (ret == 0)
		ret = total;
out_unlock:
	up_read(&orangefs_inode->xattr_sem);
	return ret;
}
Exemplo n.º 22
0
Arquivo: namei.c Projeto: Goon83/SALB
static int pvfs2_rename(
    struct inode *old_dir,
    struct dentry *old_dentry,
    struct inode *new_dir,
    struct dentry *new_dentry)
{
    int ret = -EINVAL, are_directories = 0;
    pvfs2_inode_t *pvfs2_old_parent_inode = PVFS2_I(old_dir);
    pvfs2_inode_t *pvfs2_new_parent_inode = PVFS2_I(new_dir);
    pvfs2_kernel_op_t *new_op = NULL;
    struct super_block *sb = NULL;

    gossip_debug(GOSSIP_NAME_DEBUG, "pvfs2_rename: called (%s/%s => %s/%s) ct=%d\n",
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
                atomic_read(&new_dentry->d_count));

    are_directories = S_ISDIR(old_dentry->d_inode->i_mode);
#if 0
    /* NOTE: we have no good way to keep nlink consistent for directories
     * across clients; keep constant at 1  -Phil
     */
    if (are_directories && (new_dir->i_nlink >= PVFS2_LINK_MAX))
    {
        gossip_err("pvfs2_rename: directory %s surpassed "
                    "PVFS2_LINK_MAX\n",
                    new_dentry->d_name.name);
        return -EMLINK;
    }
#endif

    new_op = op_alloc(PVFS2_VFS_OP_RENAME);
    if (!new_op)
    {
	return ret;
    }

    /*
      if no handle/fs_id is available in the parent,
      use the root handle/fs_id as specified by the
      inode's corresponding superblock
    */
    if (pvfs2_old_parent_inode &&
            pvfs2_old_parent_inode->refn.handle != PVFS_HANDLE_NULL &&
            pvfs2_old_parent_inode->refn.fs_id != PVFS_FS_ID_NULL)
    {
        new_op->upcall.req.rename.old_parent_refn =
            pvfs2_old_parent_inode->refn;
    }
    else
    {
        sb = old_dir->i_sb;
        new_op->upcall.req.rename.old_parent_refn.handle =
	    PVFS2_SB(sb)->root_handle;
        new_op->upcall.req.rename.old_parent_refn.fs_id =
	    PVFS2_SB(sb)->fs_id;
    }

    /* do the same for the new parent */
    if (pvfs2_new_parent_inode &&
            pvfs2_new_parent_inode->refn.handle != PVFS_HANDLE_NULL &&
            pvfs2_new_parent_inode->refn.fs_id != PVFS_FS_ID_NULL)
    {
        new_op->upcall.req.rename.new_parent_refn =
            pvfs2_new_parent_inode->refn;
    }
    else
    {
        sb = new_dir->i_sb;
        new_op->upcall.req.rename.new_parent_refn.handle =
	    PVFS2_SB(sb)->root_handle;
        new_op->upcall.req.rename.new_parent_refn.fs_id =
	    PVFS2_SB(sb)->fs_id;
    }
    strncpy(new_op->upcall.req.rename.d_old_name,
	    old_dentry->d_name.name, PVFS2_NAME_LEN);
    strncpy(new_op->upcall.req.rename.d_new_name,
	    new_dentry->d_name.name, PVFS2_NAME_LEN);

    ret = service_operation(
        new_op, "pvfs2_rename", 
        get_interruptible_flag(old_dentry->d_inode));

    gossip_debug(GOSSIP_NAME_DEBUG, "pvfs2_rename: got downcall status %d\n", ret);

    if (new_dentry->d_inode)
    {
        new_dentry->d_inode->i_ctime = CURRENT_TIME;
#if 0
        /* NOTE: we have no good way to keep nlink consistent for directories
         * across clients; keep constant at 1  -Phil
         */
        if (are_directories)
        {
            new_dentry->d_inode->i_nlink--;
        }
#endif
    }
#if 0
    /* NOTE: we have no good way to keep nlink consistent for directories
     * across clients; keep constant at 1  -Phil
     */
    else if (are_directories)
    {
        new_dir->i_nlink++;
        old_dir->i_nlink--;
    }
#endif

    op_release(new_op);

#ifdef PVFS2_LINUX_KERNEL_2_4
    if (ret == 0)
    {
        d_move(old_dentry, new_dentry);
    }
#endif
    return ret;
}