Orangefs: This pull request includes one fix and our "Orangefs through
the pagecache" patch series which greatly improves our small IO performance and helps us pass more xfstests than before. fix: orangefs: truncate before updating size Pagecache series: all the rest -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJc1CucAAoJEM9EDqnrzg2+2h4P/i2ktG4Zi3VDwCr1xea0bWSf kidYxzVPmGAmfC+UNMn/+X4v/R6rtHcpW/g7/0WLqhLUhRwjB1gzT6U9mHfu8BQV 1I7tg6lQqcTi4gNkBMWI4MHKRyoQ5bAgY7jFxLjqx1zj5+qxrtPn4GUCUbDBDPpP Ip9RD/izEKeG77gdSUkCD72ojHl9lqmT1Qd3k3asmozzdWzd8mdXy8EQplECo7tZ 1tLzV+BSER2BVQfmws2CCG00DLFzQRJkDYxm7I5l1xoQ/Ft8n6k/tXZ1QzkPREg2 FhaoY5eCA/2MkB0VhUKj1Y+gXNZcbys11oxcqyZZ6p2kOu+1bY+evkzwDUzsIAg+ nl1d3LoeEVKoxpa4O+vCHLF++HX8TuVHSaxvNaZPMm86gxowCh0aberyWcscGbQp m2M28WdjlzYC7uPSakoKVvF+ZBNKQP5sn6jbjYSOHAB9nFz6x5ILH3SMK8MXoZZe 2Ejd4NBmtqekdLp2MNlAWHF1O9sTagH+OqUvbNRNjrQXM3hNSgeguGx1b0E+KlT2 lwKORIVwZNZ/xuizdwM01kWRQObAmGrptlVbR4+HKqo99g9gGv6sdw//cHzo9/2S GV34cpS5VRSwHVwuzADD1A/qQ+k5xomihrpZwcqh+YOwQV16JnTHiSeTYZKVIEW8 cBiZ2k5dbKm1QcLc9tJ3 =uBS+ -----END PGP SIGNATURE----- Merge tag 'for-linus-5.2-ofs1' of git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux Pull orangefs updates from Mike Marshall: "This includes one fix and our "Orangefs through the pagecache" patch series which greatly improves our small IO performance and helps us pass more xfstests than before. Fix: - orangefs: truncate before updating size Pagecache series: - all the rest" * tag 'for-linus-5.2-ofs1' of git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux: (23 commits) orangefs: truncate before updating size orangefs: copy Orangefs-sized blocks into the pagecache if possible. orangefs: pass slot index back to readpage. orangefs: remember count when reading. orangefs: add orangefs_revalidate_mapping orangefs: implement writepages orangefs: write range tracking orangefs: avoid fsync service operation on flush orangefs: skip inode writeout if nothing to write orangefs: move do_readv_writev to direct_IO orangefs: do not return successful read when the client-core disappeared orangefs: implement writepage orangefs: migrate to generic_file_read_iter orangefs: service ops done for writeback are not killable orangefs: remove orangefs_readpages orangefs: reorganize setattr functions to track attribute changes orangefs: let setattr write to cached inode orangefs: set up and use backing_dev_info orangefs: hold i_lock during inode_getattr orangefs: update attributes rather than relying on server ...
This commit is contained in:
commit
8823880561
|
@ -142,7 +142,7 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
|||
rc = __orangefs_set_acl(inode, acl, type);
|
||||
} else {
|
||||
iattr.ia_valid = ATTR_MODE;
|
||||
rc = orangefs_inode_setattr(inode, &iattr);
|
||||
rc = __orangefs_setattr(inode, &iattr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -185,7 +185,7 @@ int orangefs_init_acl(struct inode *inode, struct inode *dir)
|
|||
inode->i_mode = mode;
|
||||
iattr.ia_mode = mode;
|
||||
iattr.ia_valid |= ATTR_MODE;
|
||||
orangefs_inode_setattr(inode, &iattr);
|
||||
__orangefs_setattr(inode, &iattr);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* (C) 2001 Clemson University and The University of Chicago
|
||||
* Copyright 2018 Omnibond Systems, L.L.C.
|
||||
*
|
||||
* See COPYING in top-level directory.
|
||||
*/
|
||||
|
@ -44,15 +45,16 @@ static int flush_racache(struct inode *inode)
|
|||
/*
|
||||
* 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)
|
||||
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_write_range *wr, int *index_return)
|
||||
{
|
||||
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;
|
||||
int buffer_index = -1;
|
||||
ssize_t ret;
|
||||
size_t copy_amount;
|
||||
|
||||
new_op = op_alloc(ORANGEFS_VFS_OP_FILE_IO);
|
||||
if (!new_op)
|
||||
|
@ -84,6 +86,10 @@ populate_shared_memory:
|
|||
new_op->upcall.req.io.buf_index = buffer_index;
|
||||
new_op->upcall.req.io.count = total_size;
|
||||
new_op->upcall.req.io.offset = *offset;
|
||||
if (type == ORANGEFS_IO_WRITE && wr) {
|
||||
new_op->upcall.uid = from_kuid(&init_user_ns, wr->uid);
|
||||
new_op->upcall.gid = from_kgid(&init_user_ns, wr->gid);
|
||||
}
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): offset: %llu total_size: %zd\n",
|
||||
|
@ -168,6 +174,9 @@ populate_shared_memory:
|
|||
* trigger the write.
|
||||
*/
|
||||
case OP_VFS_STATE_INPROGR:
|
||||
if (type == ORANGEFS_IO_READ)
|
||||
ret = -EINTR;
|
||||
else
|
||||
ret = total_size;
|
||||
break;
|
||||
default:
|
||||
|
@ -204,8 +213,25 @@ populate_shared_memory:
|
|||
* can futher be kernel-space or user-space addresses.
|
||||
* or it can pointers to struct page's
|
||||
*/
|
||||
|
||||
/*
|
||||
* When reading, readahead_size will only be zero when
|
||||
* we're doing O_DIRECT, otherwise we got here from
|
||||
* orangefs_readpage.
|
||||
*
|
||||
* If we got here from orangefs_readpage we want to
|
||||
* copy either a page or the whole file into the io
|
||||
* vector, whichever is smaller.
|
||||
*/
|
||||
if (readahead_size)
|
||||
copy_amount =
|
||||
min(new_op->downcall.resp.io.amt_complete,
|
||||
(__s64)PAGE_SIZE);
|
||||
else
|
||||
copy_amount = new_op->downcall.resp.io.amt_complete;
|
||||
|
||||
ret = orangefs_bufmap_copy_to_iovec(iter, buffer_index,
|
||||
new_op->downcall.resp.io.amt_complete);
|
||||
copy_amount);
|
||||
if (ret < 0) {
|
||||
gossip_err("%s: Failed to copy-out buffers. Please make sure that the pvfs2-client is running (%ld)\n",
|
||||
__func__, (long)ret);
|
||||
|
@ -223,246 +249,112 @@ populate_shared_memory:
|
|||
|
||||
out:
|
||||
if (buffer_index >= 0) {
|
||||
if ((readahead_size) && (type == ORANGEFS_IO_READ)) {
|
||||
/* readpage */
|
||||
*index_return = buffer_index;
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s: hold on to buffer_index :%d:\n",
|
||||
__func__, buffer_index);
|
||||
} else {
|
||||
/* O_DIRECT */
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common entry point for read/write/readv/writev
|
||||
* This function will dispatch it to either the direct I/O
|
||||
* or buffered I/O path depending on the mount options and/or
|
||||
* augmented/extended metadata attached to the file.
|
||||
* Note: File extended attributes override any mount options.
|
||||
*/
|
||||
static ssize_t do_readv_writev(enum ORANGEFS_io_type type, struct file *file,
|
||||
loff_t *offset, struct iov_iter *iter)
|
||||
int orangefs_revalidate_mapping(struct inode *inode)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_khandle *handle = &orangefs_inode->refn.khandle;
|
||||
size_t count = iov_iter_count(iter);
|
||||
ssize_t total_count = 0;
|
||||
ssize_t ret = -EINVAL;
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
unsigned long *bitlock = &orangefs_inode->bitlock;
|
||||
int ret;
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s-BEGIN(%pU): count(%d) after estimate_max_iovecs.\n",
|
||||
__func__,
|
||||
handle,
|
||||
(int)count);
|
||||
|
||||
if (type == ORANGEFS_IO_WRITE) {
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): proceeding with offset : %llu, "
|
||||
"size %d\n",
|
||||
__func__,
|
||||
handle,
|
||||
llu(*offset),
|
||||
(int)count);
|
||||
while (1) {
|
||||
ret = wait_on_bit(bitlock, 1, TASK_KILLABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
spin_lock(&inode->i_lock);
|
||||
if (test_bit(1, bitlock)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (iov_iter_count(iter)) {
|
||||
size_t each_count = iov_iter_count(iter);
|
||||
size_t amt_complete;
|
||||
|
||||
/* how much to transfer in this loop iteration */
|
||||
if (each_count > orangefs_bufmap_size_query())
|
||||
each_count = orangefs_bufmap_size_query();
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): size of each_count(%d)\n",
|
||||
__func__,
|
||||
handle,
|
||||
(int)each_count);
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): BEFORE wait_for_io: offset is %d\n",
|
||||
__func__,
|
||||
handle,
|
||||
(int)*offset);
|
||||
|
||||
ret = wait_for_direct_io(type, inode, offset, iter,
|
||||
each_count, 0);
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): return from wait_for_io:%d\n",
|
||||
__func__,
|
||||
handle,
|
||||
(int)ret);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
*offset += ret;
|
||||
total_count += ret;
|
||||
amt_complete = ret;
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): AFTER wait_for_io: offset is %d\n",
|
||||
__func__,
|
||||
handle,
|
||||
(int)*offset);
|
||||
|
||||
/*
|
||||
* if we got a short I/O operations,
|
||||
* fall out and return what we got so far
|
||||
*/
|
||||
if (amt_complete < each_count)
|
||||
if (!time_before(jiffies, orangefs_inode->mapping_time))
|
||||
break;
|
||||
} /*end while */
|
||||
spin_unlock(&inode->i_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_bit(1, bitlock);
|
||||
smp_wmb();
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
unmap_mapping_range(mapping, 0, 0, 0);
|
||||
ret = filemap_write_and_wait(mapping);
|
||||
if (!ret)
|
||||
ret = invalidate_inode_pages2(mapping);
|
||||
|
||||
orangefs_inode->mapping_time = jiffies +
|
||||
orangefs_cache_timeout_msecs*HZ/1000;
|
||||
|
||||
clear_bit(1, bitlock);
|
||||
smp_mb__after_atomic();
|
||||
wake_up_bit(bitlock, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t orangefs_file_read_iter(struct kiocb *iocb,
|
||||
struct iov_iter *iter)
|
||||
{
|
||||
int ret;
|
||||
struct orangefs_read_options *ro;
|
||||
|
||||
orangefs_stats.reads++;
|
||||
|
||||
/*
|
||||
* Remember how they set "count" in read(2) or pread(2) or whatever -
|
||||
* users can use count as a knob to control orangefs io size and later
|
||||
* we can try to help them fill as many pages as possible in readpage.
|
||||
*/
|
||||
if (!iocb->ki_filp->private_data) {
|
||||
iocb->ki_filp->private_data = kmalloc(sizeof *ro, GFP_KERNEL);
|
||||
if (!iocb->ki_filp->private_data)
|
||||
return(ENOMEM);
|
||||
ro = iocb->ki_filp->private_data;
|
||||
ro->blksiz = iter->count;
|
||||
}
|
||||
|
||||
down_read(&file_inode(iocb->ki_filp)->i_rwsem);
|
||||
ret = orangefs_revalidate_mapping(file_inode(iocb->ki_filp));
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = generic_file_read_iter(iocb, iter);
|
||||
out:
|
||||
if (total_count > 0)
|
||||
ret = total_count;
|
||||
if (ret > 0) {
|
||||
if (type == ORANGEFS_IO_READ) {
|
||||
file_accessed(file);
|
||||
} else {
|
||||
file_update_time(file);
|
||||
/*
|
||||
* Must invalidate to ensure write loop doesn't
|
||||
* prevent kernel from reading updated
|
||||
* attribute. Size probably changed because of
|
||||
* the write, and other clients could update
|
||||
* any other attribute.
|
||||
*/
|
||||
orangefs_inode->getattr_time = jiffies - 1;
|
||||
}
|
||||
}
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): Value(%d) returned.\n",
|
||||
__func__,
|
||||
handle,
|
||||
(int)ret);
|
||||
|
||||
up_read(&file_inode(iocb->ki_filp)->i_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read data from a specified offset in a file (referenced by inode).
|
||||
* Data may be placed either in a user or kernel buffer.
|
||||
*/
|
||||
ssize_t orangefs_inode_read(struct inode *inode,
|
||||
struct iov_iter *iter,
|
||||
loff_t *offset,
|
||||
loff_t readahead_size)
|
||||
static ssize_t orangefs_file_write_iter(struct kiocb *iocb,
|
||||
struct iov_iter *iter)
|
||||
{
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
size_t count = iov_iter_count(iter);
|
||||
size_t bufmap_size;
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
orangefs_stats.reads++;
|
||||
|
||||
bufmap_size = orangefs_bufmap_size_query();
|
||||
if (count > bufmap_size) {
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s: count is too large (%zd/%zd)!\n",
|
||||
__func__, count, bufmap_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU) %zd@%llu\n",
|
||||
__func__,
|
||||
&orangefs_inode->refn.khandle,
|
||||
count,
|
||||
llu(*offset));
|
||||
|
||||
ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, offset, iter,
|
||||
count, readahead_size);
|
||||
if (ret > 0)
|
||||
*offset += ret;
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"%s(%pU): Value(%zd) returned.\n",
|
||||
__func__,
|
||||
&orangefs_inode->refn.khandle,
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t orangefs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
loff_t pos = iocb->ki_pos;
|
||||
ssize_t rc = 0;
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_read_iter\n");
|
||||
|
||||
orangefs_stats.reads++;
|
||||
|
||||
rc = do_readv_writev(ORANGEFS_IO_READ, file, &pos, iter);
|
||||
iocb->ki_pos = pos;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
loff_t pos;
|
||||
ssize_t rc;
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_write_iter\n");
|
||||
|
||||
inode_lock(file->f_mapping->host);
|
||||
|
||||
/* Make sure generic_write_checks sees an up to date inode size. */
|
||||
if (file->f_flags & O_APPEND) {
|
||||
rc = orangefs_inode_getattr(file->f_mapping->host, 0, 1,
|
||||
STATX_SIZE);
|
||||
if (rc == -ESTALE)
|
||||
rc = -EIO;
|
||||
if (rc) {
|
||||
gossip_err("%s: orangefs_inode_getattr failed, "
|
||||
"rc:%zd:.\n", __func__, rc);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = generic_write_checks(iocb, iter);
|
||||
|
||||
if (rc <= 0) {
|
||||
gossip_err("%s: generic_write_checks failed, rc:%zd:.\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we are appending, generic_write_checks would have updated
|
||||
* pos to the end of the file, so we will wait till now to set
|
||||
* pos...
|
||||
*/
|
||||
pos = iocb->ki_pos;
|
||||
|
||||
rc = do_readv_writev(ORANGEFS_IO_WRITE,
|
||||
file,
|
||||
&pos,
|
||||
iter);
|
||||
if (rc < 0) {
|
||||
gossip_err("%s: do_readv_writev failed, rc:%zd:.\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
iocb->ki_pos = pos;
|
||||
int ret;
|
||||
orangefs_stats.writes++;
|
||||
|
||||
out:
|
||||
if (iocb->ki_pos > i_size_read(file_inode(iocb->ki_filp))) {
|
||||
ret = orangefs_revalidate_mapping(file_inode(iocb->ki_filp));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
inode_unlock(file->f_mapping->host);
|
||||
return rc;
|
||||
ret = generic_file_write_iter(iocb, iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -528,14 +420,13 @@ static vm_fault_t orangefs_fault(struct vm_fault *vmf)
|
|||
{
|
||||
struct file *file = vmf->vma->vm_file;
|
||||
int ret;
|
||||
|
||||
ret = orangefs_inode_getattr(file->f_mapping->host, 0, 1,
|
||||
STATX_SIZE);
|
||||
ret = orangefs_inode_getattr(file->f_mapping->host,
|
||||
ORANGEFS_GETATTR_SIZE);
|
||||
if (ret == -ESTALE)
|
||||
ret = -EIO;
|
||||
if (ret) {
|
||||
gossip_err("%s: orangefs_inode_getattr failed, ret:%d:.\n",
|
||||
__func__, ret);
|
||||
gossip_err("%s: orangefs_inode_getattr failed, "
|
||||
"ret:%d:.\n", __func__, ret);
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
return filemap_fault(vmf);
|
||||
|
@ -544,7 +435,7 @@ static vm_fault_t orangefs_fault(struct vm_fault *vmf)
|
|||
static const struct vm_operations_struct orangefs_file_vm_ops = {
|
||||
.fault = orangefs_fault,
|
||||
.map_pages = filemap_map_pages,
|
||||
.page_mkwrite = filemap_page_mkwrite,
|
||||
.page_mkwrite = orangefs_page_mkwrite,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -552,15 +443,18 @@ static const struct vm_operations_struct orangefs_file_vm_ops = {
|
|||
*/
|
||||
static int orangefs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = orangefs_revalidate_mapping(file_inode(file));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"orangefs_file_mmap: called on %s\n",
|
||||
(file ?
|
||||
(char *)file->f_path.dentry->d_name.name :
|
||||
(char *)"Unknown"));
|
||||
|
||||
if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
|
||||
return -EINVAL;
|
||||
|
||||
/* set the sequential readahead hint */
|
||||
vma->vm_flags |= VM_SEQ_READ;
|
||||
vma->vm_flags &= ~VM_RAND_READ;
|
||||
|
@ -600,8 +494,7 @@ static int orangefs_file_release(struct inode *inode, struct file *file)
|
|||
gossip_debug(GOSSIP_INODE_DEBUG,
|
||||
"flush_racache finished\n");
|
||||
}
|
||||
truncate_inode_pages(file_inode(file)->i_mapping,
|
||||
0);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -619,6 +512,11 @@ static int orangefs_fsync(struct file *file,
|
|||
ORANGEFS_I(file_inode(file));
|
||||
struct orangefs_kernel_op_s *new_op = NULL;
|
||||
|
||||
ret = filemap_write_and_wait_range(file_inode(file)->i_mapping,
|
||||
start, end);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
new_op = op_alloc(ORANGEFS_VFS_OP_FSYNC);
|
||||
if (!new_op)
|
||||
return -ENOMEM;
|
||||
|
@ -656,8 +554,8 @@ static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin)
|
|||
* NOTE: We are only interested in file size here,
|
||||
* so we set mask accordingly.
|
||||
*/
|
||||
ret = orangefs_inode_getattr(file->f_mapping->host, 0, 1,
|
||||
STATX_SIZE);
|
||||
ret = orangefs_inode_getattr(file->f_mapping->host,
|
||||
ORANGEFS_GETATTR_SIZE);
|
||||
if (ret == -ESTALE)
|
||||
ret = -EIO;
|
||||
if (ret) {
|
||||
|
@ -700,6 +598,42 @@ static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int orangefs_file_open(struct inode * inode, struct file *file)
|
||||
{
|
||||
file->private_data = NULL;
|
||||
return generic_file_open(inode, file);
|
||||
}
|
||||
|
||||
static int orangefs_flush(struct file *file, fl_owner_t id)
|
||||
{
|
||||
/*
|
||||
* This is vfs_fsync_range(file, 0, LLONG_MAX, 0) without the
|
||||
* service_operation in orangefs_fsync.
|
||||
*
|
||||
* Do not send fsync to OrangeFS server on a close. Do send fsync
|
||||
* on an explicit fsync call. This duplicates historical OrangeFS
|
||||
* behavior.
|
||||
*/
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int r;
|
||||
|
||||
kfree(file->private_data);
|
||||
file->private_data = NULL;
|
||||
|
||||
if (inode->i_state & I_DIRTY_TIME) {
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_state &= ~I_DIRTY_TIME;
|
||||
spin_unlock(&inode->i_lock);
|
||||
mark_inode_dirty_sync(inode);
|
||||
}
|
||||
|
||||
r = filemap_write_and_wait_range(file->f_mapping, 0, LLONG_MAX);
|
||||
if (r > 0)
|
||||
return 0;
|
||||
else
|
||||
return r;
|
||||
}
|
||||
|
||||
/** ORANGEFS implementation of VFS file operations */
|
||||
const struct file_operations orangefs_file_operations = {
|
||||
.llseek = orangefs_file_llseek,
|
||||
|
@ -708,7 +642,8 @@ const struct file_operations orangefs_file_operations = {
|
|||
.lock = orangefs_lock,
|
||||
.unlocked_ioctl = orangefs_ioctl,
|
||||
.mmap = orangefs_file_mmap,
|
||||
.open = generic_file_open,
|
||||
.open = orangefs_file_open,
|
||||
.flush = orangefs_flush,
|
||||
.release = orangefs_file_release,
|
||||
.fsync = orangefs_fsync,
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -76,19 +76,16 @@ static int orangefs_create(struct inode *dir,
|
|||
|
||||
d_instantiate_new(dentry, inode);
|
||||
orangefs_set_timeout(dentry);
|
||||
ORANGEFS_I(inode)->getattr_time = jiffies - 1;
|
||||
ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
|
||||
|
||||
gossip_debug(GOSSIP_NAME_DEBUG,
|
||||
"%s: dentry instantiated for %pd\n",
|
||||
__func__,
|
||||
dentry);
|
||||
|
||||
dir->i_mtime = dir->i_ctime = current_time(dir);
|
||||
memset(&iattr, 0, sizeof iattr);
|
||||
iattr.ia_valid |= ATTR_MTIME;
|
||||
orangefs_inode_setattr(dir, &iattr);
|
||||
mark_inode_dirty_sync(dir);
|
||||
iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
|
||||
iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
|
||||
__orangefs_setattr(dir, &iattr);
|
||||
ret = 0;
|
||||
out:
|
||||
op_release(new_op);
|
||||
|
@ -210,11 +207,10 @@ static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
if (!ret) {
|
||||
drop_nlink(inode);
|
||||
|
||||
dir->i_mtime = dir->i_ctime = current_time(dir);
|
||||
memset(&iattr, 0, sizeof iattr);
|
||||
iattr.ia_valid |= ATTR_MTIME;
|
||||
orangefs_inode_setattr(dir, &iattr);
|
||||
mark_inode_dirty_sync(dir);
|
||||
iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
|
||||
iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
|
||||
__orangefs_setattr(dir, &iattr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -291,19 +287,16 @@ static int orangefs_symlink(struct inode *dir,
|
|||
|
||||
d_instantiate_new(dentry, inode);
|
||||
orangefs_set_timeout(dentry);
|
||||
ORANGEFS_I(inode)->getattr_time = jiffies - 1;
|
||||
ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
|
||||
|
||||
gossip_debug(GOSSIP_NAME_DEBUG,
|
||||
"Inode (Symlink) %pU -> %pd\n",
|
||||
get_khandle_from_ino(inode),
|
||||
dentry);
|
||||
|
||||
dir->i_mtime = dir->i_ctime = current_time(dir);
|
||||
memset(&iattr, 0, sizeof iattr);
|
||||
iattr.ia_valid |= ATTR_MTIME;
|
||||
orangefs_inode_setattr(dir, &iattr);
|
||||
mark_inode_dirty_sync(dir);
|
||||
iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
|
||||
iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
|
||||
__orangefs_setattr(dir, &iattr);
|
||||
ret = 0;
|
||||
out:
|
||||
op_release(new_op);
|
||||
|
@ -360,8 +353,6 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
|
|||
|
||||
d_instantiate_new(dentry, inode);
|
||||
orangefs_set_timeout(dentry);
|
||||
ORANGEFS_I(inode)->getattr_time = jiffies - 1;
|
||||
ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
|
||||
|
||||
gossip_debug(GOSSIP_NAME_DEBUG,
|
||||
"Inode (Directory) %pU -> %pd\n",
|
||||
|
@ -372,11 +363,10 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
|
|||
* NOTE: we have no good way to keep nlink consistent for directories
|
||||
* across clients; keep constant at 1.
|
||||
*/
|
||||
dir->i_mtime = dir->i_ctime = current_time(dir);
|
||||
memset(&iattr, 0, sizeof iattr);
|
||||
iattr.ia_valid |= ATTR_MTIME;
|
||||
orangefs_inode_setattr(dir, &iattr);
|
||||
mark_inode_dirty_sync(dir);
|
||||
iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
|
||||
iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
|
||||
__orangefs_setattr(dir, &iattr);
|
||||
out:
|
||||
op_release(new_op);
|
||||
return ret;
|
||||
|
@ -389,6 +379,7 @@ static int orangefs_rename(struct inode *old_dir,
|
|||
unsigned int flags)
|
||||
{
|
||||
struct orangefs_kernel_op_s *new_op;
|
||||
struct iattr iattr;
|
||||
int ret;
|
||||
|
||||
if (flags)
|
||||
|
@ -398,7 +389,10 @@ static int orangefs_rename(struct inode *old_dir,
|
|||
"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;
|
||||
memset(&iattr, 0, sizeof iattr);
|
||||
iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
|
||||
iattr.ia_mtime = iattr.ia_ctime = current_time(new_dir);
|
||||
__orangefs_setattr(new_dir, &iattr);
|
||||
|
||||
new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
|
||||
if (!new_op)
|
||||
|
|
|
@ -538,3 +538,16 @@ int orangefs_bufmap_copy_to_iovec(struct iov_iter *iter,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void orangefs_bufmap_page_fill(void *page_to,
|
||||
int buffer_index,
|
||||
int slot_index)
|
||||
{
|
||||
struct orangefs_bufmap_desc *from;
|
||||
void *page_from;
|
||||
|
||||
from = &__orangefs_bufmap->desc_array[buffer_index];
|
||||
page_from = kmap_atomic(from->page_array[slot_index]);
|
||||
memcpy(page_to, page_from, PAGE_SIZE);
|
||||
kunmap_atomic(page_from);
|
||||
}
|
||||
|
|
|
@ -34,4 +34,6 @@ int orangefs_bufmap_copy_to_iovec(struct iov_iter *iter,
|
|||
int buffer_index,
|
||||
size_t size);
|
||||
|
||||
void orangefs_bufmap_page_fill(void *kaddr, int buffer_index, int slot_index);
|
||||
|
||||
#endif /* __ORANGEFS_BUFMAP_H */
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <linux/rwsem.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -192,7 +193,13 @@ struct orangefs_inode_s {
|
|||
sector_t last_failed_block_index_read;
|
||||
|
||||
unsigned long getattr_time;
|
||||
u32 getattr_mask;
|
||||
unsigned long mapping_time;
|
||||
int attr_valid;
|
||||
kuid_t attr_uid;
|
||||
kgid_t attr_gid;
|
||||
unsigned long bitlock;
|
||||
|
||||
DECLARE_HASHTABLE(xattr_cache, 4);
|
||||
};
|
||||
|
||||
/* per superblock private orangefs info */
|
||||
|
@ -217,6 +224,25 @@ struct orangefs_stats {
|
|||
unsigned long writes;
|
||||
};
|
||||
|
||||
struct orangefs_cached_xattr {
|
||||
struct hlist_node node;
|
||||
char key[ORANGEFS_MAX_XATTR_NAMELEN];
|
||||
char val[ORANGEFS_MAX_XATTR_VALUELEN];
|
||||
ssize_t length;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct orangefs_write_range {
|
||||
loff_t pos;
|
||||
size_t len;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
};
|
||||
|
||||
struct orangefs_read_options {
|
||||
ssize_t blksiz;
|
||||
};
|
||||
|
||||
extern struct orangefs_stats orangefs_stats;
|
||||
|
||||
/*
|
||||
|
@ -329,13 +355,15 @@ void fsid_key_table_finalize(void);
|
|||
/*
|
||||
* defined in inode.c
|
||||
*/
|
||||
vm_fault_t orangefs_page_mkwrite(struct vm_fault *);
|
||||
struct inode *orangefs_new_inode(struct super_block *sb,
|
||||
struct inode *dir,
|
||||
int mode,
|
||||
dev_t dev,
|
||||
struct orangefs_object_kref *ref);
|
||||
|
||||
int orangefs_setattr(struct dentry *dentry, struct iattr *iattr);
|
||||
int __orangefs_setattr(struct inode *, struct iattr *);
|
||||
int orangefs_setattr(struct dentry *, struct iattr *);
|
||||
|
||||
int orangefs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags);
|
||||
|
@ -355,11 +383,6 @@ ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
|||
struct inode *orangefs_iget(struct super_block *sb,
|
||||
struct orangefs_object_kref *ref);
|
||||
|
||||
ssize_t orangefs_inode_read(struct inode *inode,
|
||||
struct iov_iter *iter,
|
||||
loff_t *offset,
|
||||
loff_t readahead_size);
|
||||
|
||||
/*
|
||||
* defined in devorangefs-req.c
|
||||
*/
|
||||
|
@ -370,6 +393,15 @@ void orangefs_dev_cleanup(void);
|
|||
int is_daemon_in_service(void);
|
||||
bool __is_daemon_in_service(void);
|
||||
|
||||
/*
|
||||
* defined in file.c
|
||||
*/
|
||||
int orangefs_revalidate_mapping(struct inode *);
|
||||
ssize_t wait_for_direct_io(enum ORANGEFS_io_type, struct inode *, loff_t *,
|
||||
struct iov_iter *, size_t, loff_t, struct orangefs_write_range *, int *);
|
||||
ssize_t do_readv_writev(enum ORANGEFS_io_type, struct file *, loff_t *,
|
||||
struct iov_iter *);
|
||||
|
||||
/*
|
||||
* defined in orangefs-utils.c
|
||||
*/
|
||||
|
@ -386,12 +418,14 @@ int orangefs_inode_setxattr(struct inode *inode,
|
|||
size_t size,
|
||||
int flags);
|
||||
|
||||
int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
||||
u32 request_mask);
|
||||
#define ORANGEFS_GETATTR_NEW 1
|
||||
#define ORANGEFS_GETATTR_SIZE 2
|
||||
|
||||
int orangefs_inode_getattr(struct inode *, int);
|
||||
|
||||
int orangefs_inode_check_changed(struct inode *inode);
|
||||
|
||||
int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr);
|
||||
int orangefs_inode_setattr(struct inode *inode);
|
||||
|
||||
bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op);
|
||||
|
||||
|
@ -400,6 +434,7 @@ int orangefs_normalize_to_errno(__s32 error_code);
|
|||
extern struct mutex orangefs_request_mutex;
|
||||
extern int op_timeout_secs;
|
||||
extern int slot_timeout_secs;
|
||||
extern int orangefs_cache_timeout_msecs;
|
||||
extern int orangefs_dcache_timeout_msecs;
|
||||
extern int orangefs_getattr_timeout_msecs;
|
||||
extern struct list_head orangefs_superblocks;
|
||||
|
@ -426,6 +461,7 @@ extern const struct dentry_operations orangefs_dentry_operations;
|
|||
#define ORANGEFS_OP_CANCELLATION 4 /* this is a cancellation */
|
||||
#define ORANGEFS_OP_NO_MUTEX 8 /* don't acquire request_mutex */
|
||||
#define ORANGEFS_OP_ASYNC 16 /* Queue it, but don't wait */
|
||||
#define ORANGEFS_OP_WRITEBACK 32
|
||||
|
||||
int service_operation(struct orangefs_kernel_op_s *op,
|
||||
const char *op_name,
|
||||
|
|
|
@ -30,6 +30,7 @@ static ulong module_parm_debug_mask;
|
|||
__u64 orangefs_gossip_debug_mask;
|
||||
int op_timeout_secs = ORANGEFS_DEFAULT_OP_TIMEOUT_SECS;
|
||||
int slot_timeout_secs = ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS;
|
||||
int orangefs_cache_timeout_msecs = 50;
|
||||
int orangefs_dcache_timeout_msecs = 50;
|
||||
int orangefs_getattr_timeout_msecs = 50;
|
||||
|
||||
|
|
|
@ -62,6 +62,14 @@
|
|||
* Slots are requested and waited for,
|
||||
* the wait times out after slot_timeout_secs.
|
||||
*
|
||||
* What: /sys/fs/orangefs/cache_timeout_msecs
|
||||
* Date: Mar 2018
|
||||
* Contact: Martin Brandenburg <martin@omnibond.com>
|
||||
* Description:
|
||||
* Time in milliseconds between which
|
||||
* orangefs_revalidate_mapping will invalidate the page
|
||||
* cache.
|
||||
*
|
||||
* What: /sys/fs/orangefs/dcache_timeout_msecs
|
||||
* Date: Jul 2016
|
||||
* Contact: Martin Brandenburg <martin@omnibond.com>
|
||||
|
@ -221,6 +229,13 @@ static ssize_t sysfs_int_show(struct kobject *kobj,
|
|||
"%d\n",
|
||||
slot_timeout_secs);
|
||||
goto out;
|
||||
} else if (!strcmp(attr->attr.name,
|
||||
"cache_timeout_msecs")) {
|
||||
rc = scnprintf(buf,
|
||||
PAGE_SIZE,
|
||||
"%d\n",
|
||||
orangefs_cache_timeout_msecs);
|
||||
goto out;
|
||||
} else if (!strcmp(attr->attr.name,
|
||||
"dcache_timeout_msecs")) {
|
||||
rc = scnprintf(buf,
|
||||
|
@ -277,6 +292,9 @@ static ssize_t sysfs_int_store(struct kobject *kobj,
|
|||
} else if (!strcmp(attr->attr.name, "slot_timeout_secs")) {
|
||||
rc = kstrtoint(buf, 0, &slot_timeout_secs);
|
||||
goto out;
|
||||
} else if (!strcmp(attr->attr.name, "cache_timeout_msecs")) {
|
||||
rc = kstrtoint(buf, 0, &orangefs_cache_timeout_msecs);
|
||||
goto out;
|
||||
} else if (!strcmp(attr->attr.name, "dcache_timeout_msecs")) {
|
||||
rc = kstrtoint(buf, 0, &orangefs_dcache_timeout_msecs);
|
||||
goto out;
|
||||
|
@ -818,6 +836,9 @@ static struct orangefs_attribute op_timeout_secs_attribute =
|
|||
static struct orangefs_attribute slot_timeout_secs_attribute =
|
||||
__ATTR(slot_timeout_secs, 0664, sysfs_int_show, sysfs_int_store);
|
||||
|
||||
static struct orangefs_attribute cache_timeout_msecs_attribute =
|
||||
__ATTR(cache_timeout_msecs, 0664, sysfs_int_show, sysfs_int_store);
|
||||
|
||||
static struct orangefs_attribute dcache_timeout_msecs_attribute =
|
||||
__ATTR(dcache_timeout_msecs, 0664, sysfs_int_show, sysfs_int_store);
|
||||
|
||||
|
@ -861,6 +882,7 @@ static struct orangefs_attribute perf_time_interval_secs_attribute =
|
|||
static struct attribute *orangefs_default_attrs[] = {
|
||||
&op_timeout_secs_attribute.attr,
|
||||
&slot_timeout_secs_attribute.attr,
|
||||
&cache_timeout_msecs_attribute.attr,
|
||||
&dcache_timeout_msecs_attribute.attr,
|
||||
&getattr_timeout_msecs_attribute.attr,
|
||||
&readahead_count_attribute.attr,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* (C) 2001 Clemson University and The University of Chicago
|
||||
* Copyright 2018 Omnibond Systems, L.L.C.
|
||||
*
|
||||
* See COPYING in top-level directory.
|
||||
*/
|
||||
|
@ -135,51 +136,37 @@ static int orangefs_inode_perms(struct ORANGEFS_sys_attr_s *attrs)
|
|||
* NOTE: in kernel land, we never use the sys_attr->link_target for
|
||||
* anything, so don't bother copying it into the sys_attr object here.
|
||||
*/
|
||||
static inline int copy_attributes_from_inode(struct inode *inode,
|
||||
struct ORANGEFS_sys_attr_s *attrs,
|
||||
struct iattr *iattr)
|
||||
static inline void copy_attributes_from_inode(struct inode *inode,
|
||||
struct ORANGEFS_sys_attr_s *attrs)
|
||||
{
|
||||
umode_t tmp_mode;
|
||||
|
||||
if (!iattr || !inode || !attrs) {
|
||||
gossip_err("NULL iattr (%p), inode (%p), attrs (%p) "
|
||||
"in copy_attributes_from_inode!\n",
|
||||
iattr,
|
||||
inode,
|
||||
attrs);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* We need to be careful to only copy the attributes out of the
|
||||
* iattr object that we know are valid.
|
||||
*/
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
attrs->mask = 0;
|
||||
if (iattr->ia_valid & ATTR_UID) {
|
||||
attrs->owner = from_kuid(&init_user_ns, iattr->ia_uid);
|
||||
if (orangefs_inode->attr_valid & ATTR_UID) {
|
||||
attrs->owner = from_kuid(&init_user_ns, inode->i_uid);
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_UID;
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner);
|
||||
}
|
||||
if (iattr->ia_valid & ATTR_GID) {
|
||||
attrs->group = from_kgid(&init_user_ns, iattr->ia_gid);
|
||||
if (orangefs_inode->attr_valid & ATTR_GID) {
|
||||
attrs->group = from_kgid(&init_user_ns, inode->i_gid);
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_GID;
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group);
|
||||
}
|
||||
|
||||
if (iattr->ia_valid & ATTR_ATIME) {
|
||||
if (orangefs_inode->attr_valid & ATTR_ATIME) {
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_ATIME;
|
||||
if (iattr->ia_valid & ATTR_ATIME_SET) {
|
||||
attrs->atime = (time64_t)iattr->ia_atime.tv_sec;
|
||||
if (orangefs_inode->attr_valid & ATTR_ATIME_SET) {
|
||||
attrs->atime = (time64_t)inode->i_atime.tv_sec;
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET;
|
||||
}
|
||||
}
|
||||
if (iattr->ia_valid & ATTR_MTIME) {
|
||||
if (orangefs_inode->attr_valid & ATTR_MTIME) {
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_MTIME;
|
||||
if (iattr->ia_valid & ATTR_MTIME_SET) {
|
||||
attrs->mtime = (time64_t)iattr->ia_mtime.tv_sec;
|
||||
if (orangefs_inode->attr_valid & ATTR_MTIME_SET) {
|
||||
attrs->mtime = (time64_t)inode->i_mtime.tv_sec;
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET;
|
||||
}
|
||||
}
|
||||
if (iattr->ia_valid & ATTR_CTIME)
|
||||
if (orangefs_inode->attr_valid & ATTR_CTIME)
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_CTIME;
|
||||
|
||||
/*
|
||||
|
@ -188,36 +175,10 @@ static inline int copy_attributes_from_inode(struct inode *inode,
|
|||
* worry about ATTR_SIZE
|
||||
*/
|
||||
|
||||
if (iattr->ia_valid & ATTR_MODE) {
|
||||
tmp_mode = iattr->ia_mode;
|
||||
if (tmp_mode & (S_ISVTX)) {
|
||||
if (is_root_handle(inode)) {
|
||||
/*
|
||||
* allow sticky bit to be set on root (since
|
||||
* it shows up that way by default anyhow),
|
||||
* but don't show it to the server
|
||||
*/
|
||||
tmp_mode -= S_ISVTX;
|
||||
} else {
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG,
|
||||
"%s: setting sticky bit not supported.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_mode & (S_ISUID)) {
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG,
|
||||
"%s: setting setuid bit not supported.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
attrs->perms = ORANGEFS_util_translate_mode(tmp_mode);
|
||||
if (orangefs_inode->attr_valid & ATTR_MODE) {
|
||||
attrs->perms = ORANGEFS_util_translate_mode(inode->i_mode);
|
||||
attrs->mask |= ORANGEFS_ATTR_SYS_PERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int orangefs_inode_type(enum orangefs_ds_type objtype)
|
||||
|
@ -272,27 +233,30 @@ static int orangefs_inode_is_stale(struct inode *inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
||||
u32 request_mask)
|
||||
int orangefs_inode_getattr(struct inode *inode, int flags)
|
||||
{
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_kernel_op_s *new_op;
|
||||
loff_t inode_size;
|
||||
int ret, type;
|
||||
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
|
||||
get_khandle_from_ino(inode));
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU flags %d\n",
|
||||
__func__, get_khandle_from_ino(inode), flags);
|
||||
|
||||
if (!new && !bypass) {
|
||||
/*
|
||||
* Must have all the attributes in the mask and be within cache
|
||||
* time.
|
||||
*/
|
||||
if ((request_mask & orangefs_inode->getattr_mask) ==
|
||||
request_mask &&
|
||||
time_before(jiffies, orangefs_inode->getattr_time))
|
||||
again:
|
||||
spin_lock(&inode->i_lock);
|
||||
/* Must have all the attributes in the mask and be within cache time. */
|
||||
if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
|
||||
orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
|
||||
if (orangefs_inode->attr_valid) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
write_inode_now(inode, 1);
|
||||
goto again;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
|
||||
if (!new_op)
|
||||
|
@ -302,7 +266,7 @@ int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
|||
* Size is the hardest attribute to get. The incremental cost of any
|
||||
* other attribute is essentially zero.
|
||||
*/
|
||||
if (request_mask & STATX_SIZE || new)
|
||||
if (flags)
|
||||
new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_ALL_NOHINT;
|
||||
else
|
||||
new_op->upcall.req.getattr.mask =
|
||||
|
@ -313,13 +277,33 @@ int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
|||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
if (!new) {
|
||||
again2:
|
||||
spin_lock(&inode->i_lock);
|
||||
/* Must have all the attributes in the mask and be within cache time. */
|
||||
if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
|
||||
orangefs_inode->attr_valid || inode->i_state & I_DIRTY_PAGES) {
|
||||
if (orangefs_inode->attr_valid) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
write_inode_now(inode, 1);
|
||||
goto again2;
|
||||
}
|
||||
if (inode->i_state & I_DIRTY_PAGES) {
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG, "%s: in cache or dirty\n",
|
||||
__func__);
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (!(flags & ORANGEFS_GETATTR_NEW)) {
|
||||
ret = orangefs_inode_is_stale(inode,
|
||||
&new_op->downcall.resp.getattr.attributes,
|
||||
new_op->downcall.resp.getattr.link_target);
|
||||
if (ret) {
|
||||
ret = -ESTALE;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,30 +313,26 @@ int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
|||
case S_IFREG:
|
||||
inode->i_flags = orangefs_inode_flags(&new_op->
|
||||
downcall.resp.getattr.attributes);
|
||||
if (request_mask & STATX_SIZE || new) {
|
||||
if (flags) {
|
||||
inode_size = (loff_t)new_op->
|
||||
downcall.resp.getattr.attributes.size;
|
||||
inode->i_size = inode_size;
|
||||
inode->i_blkbits = ffs(new_op->downcall.resp.getattr.
|
||||
attributes.blksize);
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_bytes = inode_size;
|
||||
inode->i_blocks =
|
||||
(inode_size + 512 - inode_size % 512)/512;
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
break;
|
||||
case S_IFDIR:
|
||||
if (request_mask & STATX_SIZE || new) {
|
||||
if (flags) {
|
||||
inode->i_size = PAGE_SIZE;
|
||||
spin_lock(&inode->i_lock);
|
||||
inode_set_bytes(inode, inode->i_size);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
set_nlink(inode, 1);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
if (new) {
|
||||
if (flags & ORANGEFS_GETATTR_NEW) {
|
||||
inode->i_size = (loff_t)strlen(new_op->
|
||||
downcall.resp.getattr.link_target);
|
||||
ret = strscpy(orangefs_inode->link_target,
|
||||
|
@ -360,7 +340,7 @@ int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
|||
ORANGEFS_NAME_MAX);
|
||||
if (ret == -E2BIG) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
inode->i_link = orangefs_inode->link_target;
|
||||
}
|
||||
|
@ -370,7 +350,7 @@ int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
|||
/* XXX: ESTALE? This is what is done if it is not new. */
|
||||
orangefs_make_bad_inode(inode);
|
||||
ret = -ESTALE;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
inode->i_uid = make_kuid(&init_user_ns, new_op->
|
||||
|
@ -393,11 +373,9 @@ int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
|
|||
|
||||
orangefs_inode->getattr_time = jiffies +
|
||||
orangefs_getattr_timeout_msecs*HZ/1000;
|
||||
if (request_mask & STATX_SIZE || new)
|
||||
orangefs_inode->getattr_mask = STATX_BASIC_STATS;
|
||||
else
|
||||
orangefs_inode->getattr_mask = STATX_BASIC_STATS & ~STATX_SIZE;
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
spin_unlock(&inode->i_lock);
|
||||
out:
|
||||
op_release(new_op);
|
||||
return ret;
|
||||
|
@ -436,7 +414,7 @@ out:
|
|||
* issues a orangefs setattr request to make sure the new attribute values
|
||||
* take effect if successful. returns 0 on success; -errno otherwise
|
||||
*/
|
||||
int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
|
||||
int orangefs_inode_setattr(struct inode *inode)
|
||||
{
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_kernel_op_s *new_op;
|
||||
|
@ -446,24 +424,31 @@ int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
|
|||
if (!new_op)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
new_op->upcall.uid = from_kuid(&init_user_ns, orangefs_inode->attr_uid);
|
||||
new_op->upcall.gid = from_kgid(&init_user_ns, orangefs_inode->attr_gid);
|
||||
new_op->upcall.req.setattr.refn = orangefs_inode->refn;
|
||||
ret = copy_attributes_from_inode(inode,
|
||||
&new_op->upcall.req.setattr.attributes,
|
||||
iattr);
|
||||
if (ret >= 0) {
|
||||
ret = service_operation(new_op, __func__,
|
||||
get_interruptible_flag(inode));
|
||||
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG,
|
||||
"orangefs_inode_setattr: returning %d\n",
|
||||
ret);
|
||||
copy_attributes_from_inode(inode,
|
||||
&new_op->upcall.req.setattr.attributes);
|
||||
orangefs_inode->attr_valid = 0;
|
||||
if (!new_op->upcall.req.setattr.attributes.mask) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
op_release(new_op);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
ret = service_operation(new_op, __func__,
|
||||
get_interruptible_flag(inode) | ORANGEFS_OP_WRITEBACK);
|
||||
gossip_debug(GOSSIP_UTILS_DEBUG,
|
||||
"orangefs_inode_setattr: returning %d\n", ret);
|
||||
if (ret)
|
||||
orangefs_make_bad_inode(inode);
|
||||
|
||||
op_release(new_op);
|
||||
|
||||
if (ret == 0)
|
||||
orangefs_inode->getattr_time = jiffies - 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "orangefs-bufmap.h"
|
||||
|
||||
#include <linux/parser.h>
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
/* a cache for orangefs-inode objects (i.e. orangefs inode private data) */
|
||||
static struct kmem_cache *orangefs_inode_cache;
|
||||
|
@ -126,7 +127,17 @@ static struct inode *orangefs_alloc_inode(struct super_block *sb)
|
|||
|
||||
static void orangefs_free_inode(struct inode *inode)
|
||||
{
|
||||
kmem_cache_free(orangefs_inode_cache, ORANGEFS_I(inode));
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_cached_xattr *cx;
|
||||
struct hlist_node *tmp;
|
||||
int i;
|
||||
|
||||
hash_for_each_safe(orangefs_inode->xattr_cache, i, tmp, cx, node) {
|
||||
hlist_del(&cx->node);
|
||||
kfree(cx);
|
||||
}
|
||||
|
||||
kmem_cache_free(orangefs_inode_cache, orangefs_inode);
|
||||
}
|
||||
|
||||
static void orangefs_destroy_inode(struct inode *inode)
|
||||
|
@ -138,6 +149,13 @@ static void orangefs_destroy_inode(struct inode *inode)
|
|||
__func__, orangefs_inode, get_khandle_from_ino(inode));
|
||||
}
|
||||
|
||||
static int orangefs_write_inode(struct inode *inode,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_write_inode\n");
|
||||
return orangefs_inode_setattr(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: information filled in here is typically reflected in the
|
||||
* output of the system command 'df'
|
||||
|
@ -297,6 +315,7 @@ static const struct super_operations orangefs_s_ops = {
|
|||
.alloc_inode = orangefs_alloc_inode,
|
||||
.free_inode = orangefs_free_inode,
|
||||
.destroy_inode = orangefs_destroy_inode,
|
||||
.write_inode = orangefs_write_inode,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.statfs = orangefs_statfs,
|
||||
.remount_fs = orangefs_remount_fs,
|
||||
|
@ -394,15 +413,11 @@ static int orangefs_fill_sb(struct super_block *sb,
|
|||
struct orangefs_fs_mount_response *fs_mount,
|
||||
void *data, int silent)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct inode *root = NULL;
|
||||
struct dentry *root_dentry = NULL;
|
||||
int ret;
|
||||
struct inode *root;
|
||||
struct dentry *root_dentry;
|
||||
struct orangefs_object_kref root_object;
|
||||
|
||||
/* alloc and init our private orangefs sb info */
|
||||
sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
|
||||
if (!ORANGEFS_SB(sb))
|
||||
return -ENOMEM;
|
||||
ORANGEFS_SB(sb)->sb = sb;
|
||||
|
||||
ORANGEFS_SB(sb)->root_khandle = fs_mount->root_khandle;
|
||||
|
@ -425,6 +440,10 @@ static int orangefs_fill_sb(struct super_block *sb,
|
|||
sb->s_blocksize_bits = PAGE_SHIFT;
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
|
||||
ret = super_setup_bdi(sb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
root_object.khandle = ORANGEFS_SB(sb)->root_khandle;
|
||||
root_object.fs_id = ORANGEFS_SB(sb)->fs_id;
|
||||
gossip_debug(GOSSIP_SUPER_DEBUG,
|
||||
|
@ -503,6 +522,13 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
|
|||
goto free_op;
|
||||
}
|
||||
|
||||
/* alloc and init our private orangefs sb info */
|
||||
sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
|
||||
if (!ORANGEFS_SB(sb)) {
|
||||
d = ERR_PTR(-ENOMEM);
|
||||
goto free_op;
|
||||
}
|
||||
|
||||
ret = orangefs_fill_sb(sb,
|
||||
&new_op->downcall.resp.fs_mount, data,
|
||||
flags & SB_SILENT ? 1 : 0);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
|
||||
long timeout,
|
||||
bool interruptible)
|
||||
int flags)
|
||||
__acquires(op->lock);
|
||||
static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op)
|
||||
__releases(op->lock);
|
||||
|
@ -143,9 +143,7 @@ retry_servicing:
|
|||
if (!(flags & ORANGEFS_OP_NO_MUTEX))
|
||||
mutex_unlock(&orangefs_request_mutex);
|
||||
|
||||
ret = wait_for_matching_downcall(op, timeout,
|
||||
flags & ORANGEFS_OP_INTERRUPTIBLE);
|
||||
|
||||
ret = wait_for_matching_downcall(op, timeout, flags);
|
||||
gossip_debug(GOSSIP_WAIT_DEBUG,
|
||||
"%s: wait_for_matching_downcall returned %d for %p\n",
|
||||
__func__,
|
||||
|
@ -319,10 +317,12 @@ static void
|
|||
*/
|
||||
static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
|
||||
long timeout,
|
||||
bool interruptible)
|
||||
int flags)
|
||||
__acquires(op->lock)
|
||||
{
|
||||
long n;
|
||||
int writeback = flags & ORANGEFS_OP_WRITEBACK,
|
||||
interruptible = flags & ORANGEFS_OP_INTERRUPTIBLE;
|
||||
|
||||
/*
|
||||
* There's a "schedule_timeout" inside of these wait
|
||||
|
@ -330,10 +330,12 @@ static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
|
|||
* user process that needs something done and is being
|
||||
* manipulated by the client-core process.
|
||||
*/
|
||||
if (interruptible)
|
||||
if (writeback)
|
||||
n = wait_for_completion_io_timeout(&op->waitq, timeout);
|
||||
else if (!writeback && interruptible)
|
||||
n = wait_for_completion_interruptible_timeout(&op->waitq,
|
||||
timeout);
|
||||
else
|
||||
else /* !writeback && !interruptible but compiler complains */
|
||||
n = wait_for_completion_killable_timeout(&op->waitq, timeout);
|
||||
|
||||
spin_lock(&op->lock);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* (C) 2001 Clemson University and The University of Chicago
|
||||
* Copyright 2018 Omnibond Systems, L.L.C.
|
||||
*
|
||||
* See COPYING in top-level directory.
|
||||
*/
|
||||
|
@ -14,7 +15,7 @@
|
|||
#include "orangefs-bufmap.h"
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#define SYSTEM_ORANGEFS_KEY "system.pvfs2."
|
||||
#define SYSTEM_ORANGEFS_KEY_LEN 13
|
||||
|
@ -50,6 +51,35 @@ static inline int convert_to_internal_xattr_flags(int setxattr_flags)
|
|||
return internal_flag;
|
||||
}
|
||||
|
||||
static unsigned int xattr_key(const char *key)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
while (key)
|
||||
i += *key++;
|
||||
return i % 16;
|
||||
}
|
||||
|
||||
static struct orangefs_cached_xattr *find_cached_xattr(struct inode *inode,
|
||||
const char *key)
|
||||
{
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_cached_xattr *cx;
|
||||
struct hlist_head *h;
|
||||
struct hlist_node *tmp;
|
||||
h = &orangefs_inode->xattr_cache[xattr_key(key)];
|
||||
if (hlist_empty(h))
|
||||
return NULL;
|
||||
hlist_for_each_entry_safe(cx, tmp, h, node) {
|
||||
/* if (!time_before(jiffies, cx->timeout)) {
|
||||
hlist_del(&cx->node);
|
||||
kfree(cx);
|
||||
continue;
|
||||
}*/
|
||||
if (!strcmp(cx->key, key))
|
||||
return cx;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to get a specified key's attributes of a given
|
||||
|
@ -65,6 +95,7 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
|
|||
{
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_kernel_op_s *new_op = NULL;
|
||||
struct orangefs_cached_xattr *cx;
|
||||
ssize_t ret = -ENOMEM;
|
||||
ssize_t length = 0;
|
||||
int fsuid;
|
||||
|
@ -93,6 +124,27 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
|
|||
|
||||
down_read(&orangefs_inode->xattr_sem);
|
||||
|
||||
cx = find_cached_xattr(inode, name);
|
||||
if (cx && time_before(jiffies, cx->timeout)) {
|
||||
if (cx->length == -1) {
|
||||
ret = -ENODATA;
|
||||
goto out_unlock;
|
||||
} else {
|
||||
if (size == 0) {
|
||||
ret = cx->length;
|
||||
goto out_unlock;
|
||||
}
|
||||
if (cx->length > size) {
|
||||
ret = -ERANGE;
|
||||
goto out_unlock;
|
||||
}
|
||||
memcpy(buffer, cx->val, cx->length);
|
||||
memset(buffer + cx->length, 0, size - cx->length);
|
||||
ret = cx->length;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
|
||||
if (!new_op)
|
||||
goto out_unlock;
|
||||
|
@ -117,6 +169,15 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
|
|||
" does not exist!\n",
|
||||
get_khandle_from_ino(inode),
|
||||
(char *)new_op->upcall.req.getxattr.key);
|
||||
cx = kmalloc(sizeof *cx, GFP_KERNEL);
|
||||
if (cx) {
|
||||
strcpy(cx->key, name);
|
||||
cx->length = -1;
|
||||
cx->timeout = jiffies +
|
||||
orangefs_getattr_timeout_msecs*HZ/1000;
|
||||
hash_add(orangefs_inode->xattr_cache, &cx->node,
|
||||
xattr_key(cx->key));
|
||||
}
|
||||
}
|
||||
goto out_release_op;
|
||||
}
|
||||
|
@ -156,6 +217,23 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
|
|||
|
||||
ret = length;
|
||||
|
||||
if (cx) {
|
||||
strcpy(cx->key, name);
|
||||
memcpy(cx->val, buffer, length);
|
||||
cx->length = length;
|
||||
cx->timeout = jiffies + HZ;
|
||||
} else {
|
||||
cx = kmalloc(sizeof *cx, GFP_KERNEL);
|
||||
if (cx) {
|
||||
strcpy(cx->key, name);
|
||||
memcpy(cx->val, buffer, length);
|
||||
cx->length = length;
|
||||
cx->timeout = jiffies + HZ;
|
||||
hash_add(orangefs_inode->xattr_cache, &cx->node,
|
||||
xattr_key(cx->key));
|
||||
}
|
||||
}
|
||||
|
||||
out_release_op:
|
||||
op_release(new_op);
|
||||
out_unlock:
|
||||
|
@ -168,6 +246,9 @@ static int orangefs_inode_removexattr(struct inode *inode, const char *name,
|
|||
{
|
||||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_kernel_op_s *new_op = NULL;
|
||||
struct orangefs_cached_xattr *cx;
|
||||
struct hlist_head *h;
|
||||
struct hlist_node *tmp;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
|
||||
|
@ -209,6 +290,16 @@ static int orangefs_inode_removexattr(struct inode *inode, const char *name,
|
|||
"orangefs_inode_removexattr: returning %d\n", ret);
|
||||
|
||||
op_release(new_op);
|
||||
|
||||
h = &orangefs_inode->xattr_cache[xattr_key(name)];
|
||||
hlist_for_each_entry_safe(cx, tmp, h, node) {
|
||||
if (!strcmp(cx->key, name)) {
|
||||
hlist_del(&cx->node);
|
||||
kfree(cx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
up_write(&orangefs_inode->xattr_sem);
|
||||
return ret;
|
||||
|
@ -226,6 +317,9 @@ int orangefs_inode_setxattr(struct inode *inode, const char *name,
|
|||
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
|
||||
struct orangefs_kernel_op_s *new_op;
|
||||
int internal_flag = 0;
|
||||
struct orangefs_cached_xattr *cx;
|
||||
struct hlist_head *h;
|
||||
struct hlist_node *tmp;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
gossip_debug(GOSSIP_XATTR_DEBUG,
|
||||
|
@ -287,6 +381,16 @@ int orangefs_inode_setxattr(struct inode *inode, const char *name,
|
|||
|
||||
/* when request is serviced properly, free req op struct */
|
||||
op_release(new_op);
|
||||
|
||||
h = &orangefs_inode->xattr_cache[xattr_key(name)];
|
||||
hlist_for_each_entry_safe(cx, tmp, h, node) {
|
||||
if (!strcmp(cx->key, name)) {
|
||||
hlist_del(&cx->node);
|
||||
kfree(cx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
up_write(&orangefs_inode->xattr_sem);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue