aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/buffer.c9
-rw-r--r--fs/ecryptfs/file.c1
-rw-r--r--fs/ecryptfs/inode.c9
-rw-r--r--fs/ecryptfs/main.c10
-rw-r--r--fs/ecryptfs/mmap.c44
-rw-r--r--fs/ext3/xattr.c42
-rw-r--r--fs/ext4/xattr.c41
-rw-r--r--fs/jfs/jfs_txnmgr.c3
-rw-r--r--fs/libfs.c10
-rw-r--r--fs/ncpfs/inode.c16
-rw-r--r--fs/ncpfs/sock.c151
-rw-r--r--fs/sysfs/dir.c2
-rw-r--r--fs/sysfs/file.c44
-rw-r--r--fs/sysfs/sysfs.h11
14 files changed, 267 insertions, 126 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index e8504b65176..1d0852fa728 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2365,6 +2365,10 @@ failed:
}
EXPORT_SYMBOL(nobh_prepare_write);
+/*
+ * Make sure any changes to nobh_commit_write() are reflected in
+ * nobh_truncate_page(), since it doesn't call commit_write().
+ */
int nobh_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
@@ -2466,6 +2470,11 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
+ /*
+ * It would be more correct to call aops->commit_write()
+ * here, but this is more efficient.
+ */
+ SetPageUptodate(page);
set_page_dirty(page);
}
unlock_page(page);
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index bd969adf70d..7a7d25d541e 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -205,6 +205,7 @@ int ecryptfs_open_lower_file(struct file **lower_file,
{
int rc = 0;
+ flags |= O_LARGEFILE;
dget(lower_dentry);
mntget(lower_mnt);
*lower_file = dentry_open(lower_dentry, lower_mnt, flags);
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 9fa7e0b27a9..e62f3fc7241 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -168,9 +168,9 @@ static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
goto out;
}
i_size_write(inode, 0);
- ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, inode,
- ecryptfs_dentry,
- ECRYPTFS_LOWER_I_MUTEX_NOT_HELD);
+ rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode,
+ inode, ecryptfs_dentry,
+ ECRYPTFS_LOWER_I_MUTEX_NOT_HELD);
ecryptfs_inode_to_private(inode)->crypt_stat.flags |= ECRYPTFS_NEW_FILE;
out:
return rc;
@@ -200,9 +200,6 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
inode = ecryptfs_dentry->d_inode;
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
lower_flags = ((O_CREAT | O_TRUNC) & O_ACCMODE) | O_RDWR;
-#if BITS_PER_LONG != 32
- lower_flags |= O_LARGEFILE;
-#endif
lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
/* Corresponding fput() at end of this function */
if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt,
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 80044d196fe..fc4a3a22464 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -484,18 +484,12 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
struct vfsmount *lower_mnt;
memset(&nd, 0, sizeof(struct nameidata));
- rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+ rc = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
if (rc) {
ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
- goto out_free;
+ goto out;
}
lower_root = nd.dentry;
- if (!lower_root->d_inode) {
- ecryptfs_printk(KERN_WARNING,
- "No directory to interpose on\n");
- rc = -ENOENT;
- goto out_free;
- }
lower_mnt = nd.mnt;
ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 3a6f65c3f14..b731b09499c 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -238,7 +238,6 @@ int ecryptfs_do_readpage(struct file *file, struct page *page,
lower_page_data = kmap_atomic(lower_page, KM_USER1);
memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
kunmap_atomic(lower_page_data, KM_USER1);
- flush_dcache_page(lower_page);
kunmap_atomic(page_data, KM_USER0);
flush_dcache_page(page);
rc = 0;
@@ -422,9 +421,11 @@ out:
return rc;
}
-static void ecryptfs_release_lower_page(struct page *lower_page)
+static
+void ecryptfs_release_lower_page(struct page *lower_page, int page_locked)
{
- unlock_page(lower_page);
+ if (page_locked)
+ unlock_page(lower_page);
page_cache_release(lower_page);
}
@@ -445,6 +446,7 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
const struct address_space_operations *lower_a_ops;
u64 file_size;
+retry:
header_page = grab_cache_page(lower_inode->i_mapping, 0);
if (!header_page) {
ecryptfs_printk(KERN_ERR, "grab_cache_page for "
@@ -454,6 +456,14 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
}
lower_a_ops = lower_inode->i_mapping->a_ops;
rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+ if (rc) {
+ if (rc == AOP_TRUNCATED_PAGE) {
+ ecryptfs_release_lower_page(header_page, 0);
+ goto retry;
+ } else
+ ecryptfs_release_lower_page(header_page, 1);
+ goto out;
+ }
file_size = (u64)i_size_read(inode);
ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
file_size = cpu_to_be64(file_size);
@@ -465,7 +475,11 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file,
if (rc < 0)
ecryptfs_printk(KERN_ERR, "Error commiting header page "
"write\n");
- ecryptfs_release_lower_page(header_page);
+ if (rc == AOP_TRUNCATED_PAGE) {
+ ecryptfs_release_lower_page(header_page, 0);
+ goto retry;
+ } else
+ ecryptfs_release_lower_page(header_page, 1);
lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty_sync(inode);
out:
@@ -491,7 +505,8 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode,
goto out;
}
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
- if (!lower_dentry->d_inode->i_op->getxattr) {
+ if (!lower_dentry->d_inode->i_op->getxattr ||
+ !lower_dentry->d_inode->i_op->setxattr) {
printk(KERN_WARNING
"No support for setting xattr in lower filesystem\n");
rc = -ENOSYS;
@@ -553,6 +568,7 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
{
int rc = 0;
+retry:
*lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index);
if (!(*lower_page)) {
rc = -EINVAL;
@@ -566,15 +582,18 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
byte_offset,
region_bytes);
if (rc) {
- ecryptfs_printk(KERN_ERR, "prepare_write for "
+ if (rc == AOP_TRUNCATED_PAGE) {
+ ecryptfs_release_lower_page(*lower_page, 0);
+ goto retry;
+ } else {
+ ecryptfs_printk(KERN_ERR, "prepare_write for "
"lower_page_index = [0x%.16x] failed; rc = "
"[%d]\n", lower_page_index, rc);
+ ecryptfs_release_lower_page(*lower_page, 1);
+ (*lower_page) = NULL;
+ }
}
out:
- if (rc && (*lower_page)) {
- ecryptfs_release_lower_page(*lower_page);
- (*lower_page) = NULL;
- }
return rc;
}
@@ -588,16 +607,19 @@ ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
struct file *lower_file, int byte_offset,
int region_size)
{
+ int page_locked = 1;
int rc = 0;
rc = lower_inode->i_mapping->a_ops->commit_write(
lower_file, lower_page, byte_offset, region_size);
+ if (rc == AOP_TRUNCATED_PAGE)
+ page_locked = 0;
if (rc < 0) {
ecryptfs_printk(KERN_ERR,
"Error committing write; rc = [%d]\n", rc);
} else
rc = 0;
- ecryptfs_release_lower_page(lower_page);
+ ecryptfs_release_lower_page(lower_page, page_locked);
return rc;
}
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index 99857a400f4..12f7dda1232 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -475,8 +475,15 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode,
struct buffer_head *bh)
{
struct mb_cache_entry *ce = NULL;
+ int error = 0;
ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr);
+ error = ext3_journal_get_write_access(handle, bh);
+ if (error)
+ goto out;
+
+ lock_buffer(bh);
+
if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
ea_bdebug(bh, "refcount now=0; freeing");
if (ce)
@@ -485,21 +492,20 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode,
get_bh(bh);
ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
} else {
- if (ext3_journal_get_write_access(handle, bh) == 0) {
- lock_buffer(bh);
- BHDR(bh)->h_refcount = cpu_to_le32(
+ BHDR(bh)->h_refcount = cpu_to_le32(
le32_to_cpu(BHDR(bh)->h_refcount) - 1);
- ext3_journal_dirty_metadata(handle, bh);
- if (IS_SYNC(inode))
- handle->h_sync = 1;
- DQUOT_FREE_BLOCK(inode, 1);
- unlock_buffer(bh);
- ea_bdebug(bh, "refcount now=%d; releasing",
- le32_to_cpu(BHDR(bh)->h_refcount));
- }
+ error = ext3_journal_dirty_metadata(handle, bh);
+ handle->h_sync = 1;
+ DQUOT_FREE_BLOCK(inode, 1);
+ ea_bdebug(bh, "refcount now=%d; releasing",
+ le32_to_cpu(BHDR(bh)->h_refcount));
if (ce)
mb_cache_entry_release(ce);
}
+ unlock_buffer(bh);
+out:
+ ext3_std_error(inode->i_sb, error);
+ return;
}
struct ext3_xattr_info {
@@ -675,7 +681,7 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode,
struct buffer_head *new_bh = NULL;
struct ext3_xattr_search *s = &bs->s;
struct mb_cache_entry *ce = NULL;
- int error;
+ int error = 0;
#define header(x) ((struct ext3_xattr_header *)(x))
@@ -684,16 +690,17 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode,
if (s->base) {
ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev,
bs->bh->b_blocknr);
+ error = ext3_journal_get_write_access(handle, bs->bh);
+ if (error)
+ goto cleanup;
+ lock_buffer(bs->bh);
+
if (header(s->base)->h_refcount == cpu_to_le32(1)) {
if (ce) {
mb_cache_entry_free(ce);
ce = NULL;
}
ea_bdebug(bs->bh, "modifying in-place");
- error = ext3_journal_get_write_access(handle, bs->bh);
- if (error)
- goto cleanup;
- lock_buffer(bs->bh);
error = ext3_xattr_set_entry(i, s);
if (!error) {
if (!IS_LAST_ENTRY(s->first))
@@ -713,6 +720,9 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode,
} else {
int offset = (char *)s->here - bs->bh->b_data;
+ unlock_buffer(bs->bh);
+ journal_release_buffer(handle, bs->bh);
+
if (ce) {
mb_cache_entry_release(ce);
ce = NULL;
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index dc969c357aa..e832e96095b 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -475,8 +475,14 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
struct buffer_head *bh)
{
struct mb_cache_entry *ce = NULL;
+ int error = 0;
ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr);
+ error = ext4_journal_get_write_access(handle, bh);
+ if (error)
+ goto out;
+
+ lock_buffer(bh);
if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
ea_bdebug(bh, "refcount now=0; freeing");
if (ce)
@@ -485,21 +491,21 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
get_bh(bh);
ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
} else {
- if (ext4_journal_get_write_access(handle, bh) == 0) {
- lock_buffer(bh);
- BHDR(bh)->h_refcount = cpu_to_le32(
+ BHDR(bh)->h_refcount = cpu_to_le32(
le32_to_cpu(BHDR(bh)->h_refcount) - 1);
- ext4_journal_dirty_metadata(handle, bh);
- if (IS_SYNC(inode))
- handle->h_sync = 1;
- DQUOT_FREE_BLOCK(inode, 1);
- unlock_buffer(bh);
- ea_bdebug(bh, "refcount now=%d; releasing",
- le32_to_cpu(BHDR(bh)->h_refcount));
- }
+ error = ext4_journal_dirty_metadata(handle, bh);
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+ DQUOT_FREE_BLOCK(inode, 1);
+ ea_bdebug(bh, "refcount now=%d; releasing",
+ le32_to_cpu(BHDR(bh)->h_refcount));
if (ce)
mb_cache_entry_release(ce);
}
+ unlock_buffer(bh);
+out:
+ ext4_std_error(inode->i_sb, error);
+ return;
}
struct ext4_xattr_info {
@@ -675,7 +681,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
struct buffer_head *new_bh = NULL;
struct ext4_xattr_search *s = &bs->s;
struct mb_cache_entry *ce = NULL;
- int error;
+ int error = 0;
#define header(x) ((struct ext4_xattr_header *)(x))
@@ -684,16 +690,17 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (s->base) {
ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev,
bs->bh->b_blocknr);
+ error = ext4_journal_get_write_access(handle, bs->bh);
+ if (error)
+ goto cleanup;
+ lock_buffer(bs->bh);
+
if (header(s->base)->h_refcount == cpu_to_le32(1)) {
if (ce) {
mb_cache_entry_free(ce);
ce = NULL;
}
ea_bdebug(bs->bh, "modifying in-place");
- error = ext4_journal_get_write_access(handle, bs->bh);
- if (error)
- goto cleanup;
- lock_buffer(bs->bh);
error = ext4_xattr_set_entry(i, s);
if (!error) {
if (!IS_LAST_ENTRY(s->first))
@@ -713,6 +720,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
} else {
int offset = (char *)s->here - bs->bh->b_data;
+ unlock_buffer(bs->bh);
+ jbd2_journal_release_buffer(handle, bs->bh);
if (ce) {
mb_cache_entry_release(ce);
ce = NULL;
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 6988a1082f5..03893acbfda 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -1919,7 +1919,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* header ?
*/
if (tlck->type & tlckTRUNCATE) {
- pxd_t pxd; /* truncated extent of xad */
+ /* This odd declaration suppresses a bogus gcc warning */
+ pxd_t pxd = pxd; /* truncated extent of xad */
int twm;
/*
diff --git a/fs/libfs.c b/fs/libfs.c
index cf79196535e..d93842d3c0a 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -190,6 +190,10 @@ const struct inode_operations simple_dir_inode_operations = {
.lookup = simple_lookup,
};
+static const struct super_operations simple_super_operations = {
+ .statfs = simple_statfs,
+};
+
/*
* Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
* will never be mountable)
@@ -199,7 +203,6 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name,
struct vfsmount *mnt)
{
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
- static const struct super_operations default_ops = {.statfs = simple_statfs};
struct dentry *dentry;
struct inode *root;
struct qstr d_name = {.name = name, .len = strlen(name)};
@@ -212,7 +215,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name,
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = magic;
- s->s_op = ops ? ops : &default_ops;
+ s->s_op = ops ? ops : &simple_super_operations;
s->s_time_gran = 1;
root = new_inode(s);
if (!root)
@@ -359,7 +362,6 @@ int simple_commit_write(struct file *file, struct page *page,
int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files)
{
- static struct super_operations s_ops = {.statfs = simple_statfs};
struct inode *inode;
struct dentry *root;
struct dentry *dentry;
@@ -368,7 +370,7 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
s->s_blocksize = PAGE_CACHE_SIZE;
s->s_blocksize_bits = PAGE_CACHE_SHIFT;
s->s_magic = magic;
- s->s_op = &s_ops;
+ s->s_op = &simple_super_operations;
s->s_time_gran = 1;
inode = new_inode(s);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 14939ddf74f..7285c94956c 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -576,6 +576,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
server->packet = vmalloc(NCP_PACKET_SIZE);
if (server->packet == NULL)
goto out_nls;
+ server->txbuf = vmalloc(NCP_PACKET_SIZE);
+ if (server->txbuf == NULL)
+ goto out_packet;
+ server->rxbuf = vmalloc(NCP_PACKET_SIZE);
+ if (server->rxbuf == NULL)
+ goto out_txbuf;
sock->sk->sk_data_ready = ncp_tcp_data_ready;
sock->sk->sk_error_report = ncp_tcp_error_report;
@@ -597,7 +603,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
error = ncp_connect(server);
ncp_unlock_server(server);
if (error < 0)
- goto out_packet;
+ goto out_rxbuf;
DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
@@ -666,8 +672,12 @@ out_disconnect:
ncp_lock_server(server);
ncp_disconnect(server);
ncp_unlock_server(server);
-out_packet:
+out_rxbuf:
ncp_stop_tasks(server);
+ vfree(server->rxbuf);
+out_txbuf:
+ vfree(server->txbuf);
+out_packet:
vfree(server->packet);
out_nls:
#ifdef CONFIG_NCPFS_NLS
@@ -723,6 +733,8 @@ static void ncp_put_super(struct super_block *sb)
kfree(server->priv.data);
kfree(server->auth.object_name);
+ vfree(server->rxbuf);
+ vfree(server->txbuf);
vfree(server->packet);
sb->s_fs_info = NULL;
kfree(server);
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index e496d8b65e9..e37df8d5fe7 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -14,6 +14,7 @@
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
+#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/in.h>
#include <linux/net.h>
@@ -55,10 +56,11 @@ static int _send(struct socket *sock, const void *buff, int len)
struct ncp_request_reply {
struct list_head req;
wait_queue_head_t wq;
- struct ncp_reply_header* reply_buf;
+ atomic_t refs;
+ unsigned char* reply_buf;
size_t datalen;
int result;
- enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE } status;
+ enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
struct kvec* tx_ciov;
size_t tx_totallen;
size_t tx_iovlen;
@@ -67,6 +69,32 @@ struct ncp_request_reply {
u_int32_t sign[6];
};
+static inline struct ncp_request_reply* ncp_alloc_req(void)
+{
+ struct ncp_request_reply *req;
+
+ req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
+ if (!req)
+ return NULL;
+
+ init_waitqueue_head(&req->wq);
+ atomic_set(&req->refs, (1));
+ req->status = RQ_IDLE;
+
+ return req;
+}
+
+static void ncp_req_get(struct ncp_request_reply *req)
+{
+ atomic_inc(&req->refs);
+}
+
+static void ncp_req_put(struct ncp_request_reply *req)
+{
+ if (atomic_dec_and_test(&req->refs))
+ kfree(req);
+}
+
void ncp_tcp_data_ready(struct sock *sk, int len)
{
struct ncp_server *server = sk->sk_user_data;
@@ -101,14 +129,17 @@ void ncpdgram_timeout_call(unsigned long v)
schedule_work(&server->timeout_tq);
}
-static inline void ncp_finish_request(struct ncp_request_reply *req, int result)
+static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
{
req->result = result;
+ if (req->status != RQ_ABANDONED)
+ memcpy(req->reply_buf, server->rxbuf, req->datalen);
req->status = RQ_DONE;
wake_up_all(&req->wq);
+ ncp_req_put(req);
}
-static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request_reply *aborted, int err)
+static void __abort_ncp_connection(struct ncp_server *server)
{
struct ncp_request_reply *req;
@@ -118,31 +149,19 @@ static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request
req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
list_del_init(&req->req);
- if (req == aborted) {
- ncp_finish_request(req, err);
- } else {
- ncp_finish_request(req, -EIO);
- }
+ ncp_finish_request(server, req, -EIO);
}
req = server->rcv.creq;
if (req) {
server->rcv.creq = NULL;
- if (req == aborted) {
- ncp_finish_request(req, err);
- } else {
- ncp_finish_request(req, -EIO);
- }
+ ncp_finish_request(server, req, -EIO);
server->rcv.ptr = NULL;
server->rcv.state = 0;
}
req = server->tx.creq;
if (req) {
server->tx.creq = NULL;
- if (req == aborted) {
- ncp_finish_request(req, err);
- } else {
- ncp_finish_request(req, -EIO);
- }
+ ncp_finish_request(server, req, -EIO);
}
}
@@ -160,10 +179,12 @@ static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_req
break;
case RQ_QUEUED:
list_del_init(&req->req);
- ncp_finish_request(req, err);
+ ncp_finish_request(server, req, err);
break;
case RQ_INPROGRESS:
- __abort_ncp_connection(server, req, err);
+ req->status = RQ_ABANDONED;
+ break;
+ case RQ_ABANDONED:
break;
}
}
@@ -177,7 +198,7 @@ static inline void ncp_abort_request(struct ncp_server *server, struct ncp_reque
static inline void __ncptcp_abort(struct ncp_server *server)
{
- __abort_ncp_connection(server, NULL, 0);
+ __abort_ncp_connection(server);
}
static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
@@ -294,6 +315,11 @@ static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_r
static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
{
+ /* we copy the data so that we do not depend on the caller
+ staying alive */
+ memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
+ req->tx_iov[1].iov_base = server->txbuf;
+
if (server->ncp_sock->type == SOCK_STREAM)
ncptcp_start_request(server, req);
else
@@ -308,6 +334,7 @@ static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *
printk(KERN_ERR "ncpfs: tcp: Server died\n");
return -EIO;
}
+ ncp_req_get(req);
if (server->tx.creq || server->rcv.creq) {
req->status = RQ_QUEUED;
list_add_tail(&req->req, &server->tx.requests);
@@ -409,7 +436,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
server->timeout_last = NCP_MAX_RPC_TIMEOUT;
mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
} else if (reply.type == NCP_REPLY) {
- result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT);
+ result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
#ifdef CONFIG_NCPFS_PACKET_SIGNING
if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
if (result < 8 + 8) {
@@ -419,7 +446,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
result -= 8;
hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
- if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) {
+ if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
printk(KERN_INFO "ncpfs: Signature violation\n");
result = -EIO;
}
@@ -428,7 +455,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
#endif
del_timer(&server->timeout_tm);
server->rcv.creq = NULL;
- ncp_finish_request(req, result);
+ ncp_finish_request(server, req, result);
__ncp_next_request(server);
mutex_unlock(&server->rcv.creq_mutex);
continue;
@@ -478,12 +505,6 @@ void ncpdgram_timeout_proc(struct work_struct *work)
mutex_unlock(&server->rcv.creq_mutex);
}
-static inline void ncp_init_req(struct ncp_request_reply* req)
-{
- init_waitqueue_head(&req->wq);
- req->status = RQ_IDLE;
-}
-
static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
{
int result;
@@ -601,8 +622,8 @@ skipdata:;
goto skipdata;
}
req->datalen = datalen - 8;
- req->reply_buf->type = NCP_REPLY;
- server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2;
+ ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
+ server->rcv.ptr = server->rxbuf + 2;
server->rcv.len = datalen - 10;
server->rcv.state = 1;
break;
@@ -615,12 +636,12 @@ skipdata:;
case 1:
req = server->rcv.creq;
if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
- if (req->reply_buf->sequence != server->sequence) {
+ if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
__ncp_abort_request(server, req, -EIO);
return -EIO;
}
- if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) {
+ if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
__ncp_abort_request(server, req, -EIO);
return -EIO;
@@ -628,14 +649,14 @@ skipdata:;
}
#ifdef CONFIG_NCPFS_PACKET_SIGNING
if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
- if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
+ if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
__ncp_abort_request(server, req, -EIO);
return -EIO;
}
}
#endif
- ncp_finish_request(req, req->datalen);
+ ncp_finish_request(server, req, req->datalen);
nextreq:;
__ncp_next_request(server);
case 2:
@@ -645,7 +666,7 @@ skipdata:;
server->rcv.state = 0;
break;
case 3:
- ncp_finish_request(server->rcv.creq, -EIO);
+ ncp_finish_request(server, server->rcv.creq, -EIO);
goto nextreq;
case 5:
info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
@@ -675,28 +696,39 @@ void ncp_tcp_tx_proc(struct work_struct *work)
}
static int do_ncp_rpc_call(struct ncp_server *server, int size,
- struct ncp_reply_header* reply_buf, int max_reply_size)
+ unsigned char* reply_buf, int max_reply_size)
{
int result;
- struct ncp_request_reply req;
-
- ncp_init_req(&req);
- req.reply_buf = reply_buf;
- req.datalen = max_reply_size;
- req.tx_iov[1].iov_base = server->packet;
- req.tx_iov[1].iov_len = size;
- req.tx_iovlen = 1;
- req.tx_totallen = size;
- req.tx_type = *(u_int16_t*)server->packet;
-
- result = ncp_add_request(server, &req);
- if (result < 0) {
- return result;
- }
- if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) {
- ncp_abort_request(server, &req, -EIO);
+ struct ncp_request_reply *req;
+
+ req = ncp_alloc_req();
+ if (!req)
+ return -ENOMEM;
+
+ req->reply_buf = reply_buf;
+ req->datalen = max_reply_size;
+ req->tx_iov[1].iov_base = server->packet;
+ req->tx_iov[1].iov_len = size;
+ req->tx_iovlen = 1;
+ req->tx_totallen = size;
+ req->tx_type = *(u_int16_t*)server->packet;
+
+ result = ncp_add_request(server, req);
+ if (result < 0)
+ goto out;
+
+ if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
+ ncp_abort_request(server, req, -EINTR);
+ result = -EINTR;
+ goto out;
}
- return req.result;
+
+ result = req->result;
+
+out:
+ ncp_req_put(req);
+
+ return result;
}
/*
@@ -751,11 +783,6 @@ static int ncp_do_request(struct ncp_server *server, int size,
DDPRINTK("do_ncp_rpc_call returned %d\n", result);
- if (result < 0) {
- /* There was a problem with I/O, so the connections is
- * no longer usable. */
- ncp_invalidate_conn(server);
- }
return result;
}
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 8813990304f..85a668680f8 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -431,6 +431,8 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
new_parent_dentry = new_parent ?
new_parent->dentry : sysfs_mount->mnt_sb->s_root;
+ if (old_parent_dentry->d_inode == new_parent_dentry->d_inode)
+ return 0; /* nothing to move */
again:
mutex_lock(&old_parent_dentry->d_inode->i_mutex);
if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) {
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 98b0910ad80..8d4d839a9d8 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -502,6 +502,30 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
/**
+ * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @group: group name.
+ */
+int sysfs_add_file_to_group(struct kobject *kobj,
+ const struct attribute *attr, const char *group)
+{
+ struct dentry *dir;
+ int error;
+
+ dir = lookup_one_len(group, kobj->dentry, strlen(group));
+ if (IS_ERR(dir))
+ error = PTR_ERR(dir);
+ else {
+ error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR);
+ dput(dir);
+ }
+ return error;
+}
+EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
+
+
+/**
* sysfs_update_file - update the modified timestamp on an object attribute.
* @kobj: object we're acting for.
* @attr: attribute descriptor.
@@ -586,6 +610,26 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
}
+/**
+ * sysfs_remove_file_from_group - remove an attribute file from a group.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @group: group name.
+ */
+void sysfs_remove_file_from_group(struct kobject *kobj,
+ const struct attribute *attr, const char *group)
+{
+ struct dentry *dir;
+
+ dir = lookup_one_len(group, kobj->dentry, strlen(group));
+ if (!IS_ERR(dir)) {
+ sysfs_hash_and_remove(dir, attr->name);
+ dput(dir);
+ }
+}
+EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
+
+
EXPORT_SYMBOL_GPL(sysfs_create_file);
EXPORT_SYMBOL_GPL(sysfs_remove_file);
EXPORT_SYMBOL_GPL(sysfs_update_file);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index d976b000554..a77c57e5a6d 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -1,3 +1,14 @@
+struct sysfs_dirent {
+ atomic_t s_count;
+ struct list_head s_sibling;
+ struct list_head s_children;
+ void * s_element;
+ int s_type;
+ umode_t s_mode;
+ struct dentry * s_dentry;
+ struct iattr * s_iattr;
+ atomic_t s_event;
+};
extern struct vfsmount * sysfs_mount;
extern struct kmem_cache *sysfs_dir_cachep;