/* * 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; }
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; }
/* * 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; }
/* * 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; }
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; }
/* * 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; }
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; }
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; }
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."); } }
/* 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; }
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; }
/* * 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; }
/* * 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; }
/* * 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; }
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; }
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; }
/* * 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; }
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); }
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; }
/* * 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; }
/* * 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; }
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; }