aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/file.c3
-rw-r--r--fs/aio.c59
-rw-r--r--fs/autofs4/autofs_i.h15
-rw-r--r--fs/autofs4/expire.c16
-rw-r--r--fs/autofs4/inode.c1
-rw-r--r--fs/autofs4/waitq.c22
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/bio.c2
-rw-r--r--fs/buffer.c22
-rw-r--r--fs/cifs/AUTHORS24
-rw-r--r--fs/cifs/CHANGES39
-rw-r--r--fs/cifs/README43
-rw-r--r--fs/cifs/TODO30
-rw-r--r--fs/cifs/cifs_debug.c43
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/cifs_unicode.c4
-rw-r--r--fs/cifs/cifsencrypt.c16
-rw-r--r--fs/cifs/cifsfs.c34
-rw-r--r--fs/cifs/cifsfs.h8
-rw-r--r--fs/cifs/cifsglob.h18
-rw-r--r--fs/cifs/cifspdu.h71
-rw-r--r--fs/cifs/cifsproto.h109
-rw-r--r--fs/cifs/cifssmb.c436
-rw-r--r--fs/cifs/connect.c743
-rw-r--r--fs/cifs/dir.c189
-rw-r--r--fs/cifs/fcntl.c3
-rw-r--r--fs/cifs/file.c15
-rw-r--r--fs/cifs/inode.c106
-rw-r--r--fs/cifs/ioctl.c75
-rw-r--r--fs/cifs/link.c18
-rw-r--r--fs/cifs/misc.c160
-rw-r--r--fs/cifs/netmisc.c5
-rw-r--r--fs/cifs/readdir.c120
-rw-r--r--fs/cifs/smberr.h231
-rw-r--r--fs/cifs/transport.c54
-rw-r--r--fs/cifs/xattr.c51
-rw-r--r--fs/compat.c6
-rw-r--r--fs/ext3/inode.c144
-rw-r--r--fs/fcntl.c3
-rw-r--r--fs/fs-writeback.c4
-rw-r--r--fs/hfs/mdb.c5
-rw-r--r--fs/hfs/super.c8
-rw-r--r--fs/hfsplus/super.c6
-rw-r--r--fs/hostfs/hostfs_kern.c2
-rw-r--r--fs/jffs2/file.c3
-rw-r--r--fs/jfs/inode.c35
-rw-r--r--fs/jfs/jfs_dmap.c12
-rw-r--r--fs/jfs/jfs_dtree.c6
-rw-r--r--fs/jfs/jfs_imap.c84
-rw-r--r--fs/jfs/jfs_incore.h1
-rw-r--r--fs/jfs/jfs_logmgr.c150
-rw-r--r--fs/jfs/jfs_logmgr.h9
-rw-r--r--fs/jfs/jfs_metapage.c908
-rw-r--r--fs/jfs/jfs_metapage.h80
-rw-r--r--fs/jfs/jfs_mount.c5
-rw-r--r--fs/jfs/jfs_txnmgr.c166
-rw-r--r--fs/jfs/jfs_umount.c16
-rw-r--r--fs/jfs/jfs_xtree.c61
-rw-r--r--fs/jfs/resize.c3
-rw-r--r--fs/jfs/super.c37
-rw-r--r--fs/mpage.c94
-rw-r--r--fs/proc/base.c32
-rw-r--r--fs/reiserfs/bitmap.c11
-rw-r--r--fs/reiserfs/dir.c8
-rw-r--r--fs/reiserfs/file.c13
-rw-r--r--fs/reiserfs/inode.c14
-rw-r--r--fs/reiserfs/item_ops.c5
-rw-r--r--fs/reiserfs/journal.c14
-rw-r--r--fs/reiserfs/objectid.c18
-rw-r--r--fs/reiserfs/procfs.c4
-rw-r--r--fs/reiserfs/stree.c51
-rw-r--r--fs/reiserfs/super.c35
-rw-r--r--fs/seq_file.c9
-rw-r--r--fs/sysfs/file.c4
-rw-r--r--fs/udf/file.c6
-rw-r--r--fs/udf/inode.c4
76 files changed, 3107 insertions, 1757 deletions
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 6b6bb7c8abf6..23c125128024 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -131,8 +131,7 @@ static int afs_file_readpage(struct file *file, struct page *page)
vnode = AFS_FS_I(inode);
- if (!PageLocked(page))
- PAGE_BUG(page);
+ BUG_ON(!PageLocked(page));
ret = -ESTALE;
if (vnode->flags & AFS_VNODE_DELETED)
diff --git a/fs/aio.c b/fs/aio.c
index a82214d2e46d..7afa222f6802 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -40,9 +40,6 @@
#define dprintk(x...) do { ; } while (0)
#endif
-static long aio_run = 0; /* for testing only */
-static long aio_wakeups = 0; /* for testing only */
-
/*------ sysctl variables----*/
atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */
unsigned aio_max_nr = 0x10000; /* system wide maximum number of aio requests */
@@ -405,7 +402,6 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
req->ki_ctx = ctx;
req->ki_cancel = NULL;
req->ki_retry = NULL;
- req->ki_obj.user = NULL;
req->ki_dtor = NULL;
req->private = NULL;
INIT_LIST_HEAD(&req->ki_run_list);
@@ -451,11 +447,6 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
{
if (req->ki_dtor)
req->ki_dtor(req);
- req->ki_ctx = NULL;
- req->ki_filp = NULL;
- req->ki_obj.user = NULL;
- req->ki_dtor = NULL;
- req->private = NULL;
kmem_cache_free(kiocb_cachep, req);
ctx->reqs_active--;
@@ -623,7 +614,6 @@ static inline int __queue_kicked_iocb(struct kiocb *iocb)
if (list_empty(&iocb->ki_run_list)) {
list_add_tail(&iocb->ki_run_list,
&ctx->run_list);
- iocb->ki_queued++;
return 1;
}
return 0;
@@ -664,10 +654,8 @@ static ssize_t aio_run_iocb(struct kiocb *iocb)
}
if (!(iocb->ki_retried & 0xff)) {
- pr_debug("%ld retry: %d of %d (kick %ld, Q %ld run %ld, wake %ld)\n",
- iocb->ki_retried,
- iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
- iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
+ pr_debug("%ld retry: %d of %d\n", iocb->ki_retried,
+ iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
}
if (!(retry = iocb->ki_retry)) {
@@ -774,7 +762,6 @@ out:
static int __aio_run_iocbs(struct kioctx *ctx)
{
struct kiocb *iocb;
- int count = 0;
LIST_HEAD(run_list);
list_splice_init(&ctx->run_list, &run_list);
@@ -789,9 +776,7 @@ static int __aio_run_iocbs(struct kioctx *ctx)
aio_run_iocb(iocb);
if (__aio_put_req(ctx, iocb)) /* drop extra ref */
put_ioctx(ctx);
- count++;
}
- aio_run++;
if (!list_empty(&ctx->run_list))
return 1;
return 0;
@@ -890,10 +875,8 @@ static void queue_kicked_iocb(struct kiocb *iocb)
spin_lock_irqsave(&ctx->ctx_lock, flags);
run = __queue_kicked_iocb(iocb);
spin_unlock_irqrestore(&ctx->ctx_lock, flags);
- if (run) {
+ if (run)
aio_queue_work(ctx);
- aio_wakeups++;
- }
}
/*
@@ -913,7 +896,6 @@ void fastcall kick_iocb(struct kiocb *iocb)
return;
}
- iocb->ki_kicked++;
/* If its already kicked we shouldn't queue it again */
if (!kiocbTryKick(iocb)) {
queue_kicked_iocb(iocb);
@@ -984,7 +966,8 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
tail = info->tail;
event = aio_ring_event(info, tail, KM_IRQ0);
- tail = (tail + 1) % info->nr;
+ if (++tail >= info->nr)
+ tail = 0;
event->obj = (u64)(unsigned long)iocb->ki_obj.user;
event->data = iocb->ki_user_data;
@@ -1008,10 +991,8 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
pr_debug("added to ring %p at [%lu]\n", iocb, tail);
- pr_debug("%ld retries: %d of %d (kicked %ld, Q %ld run %ld wake %ld)\n",
- iocb->ki_retried,
- iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
- iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
+ pr_debug("%ld retries: %d of %d\n", iocb->ki_retried,
+ iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
put_rq:
/* everything turned out well, dispose of the aiocb. */
ret = __aio_put_req(ctx, iocb);
@@ -1119,7 +1100,6 @@ static int read_events(struct kioctx *ctx,
int i = 0;
struct io_event ent;
struct aio_timeout to;
- int event_loop = 0; /* testing only */
int retry = 0;
/* needed to zero any padding within an entry (there shouldn't be
@@ -1186,7 +1166,6 @@ retry:
if (to.timed_out) /* Only check after read evt */
break;
schedule();
- event_loop++;
if (signal_pending(tsk)) {
ret = -EINTR;
break;
@@ -1214,9 +1193,6 @@ retry:
if (timeout)
clear_timeout(&to);
out:
- pr_debug("event loop executed %d times\n", event_loop);
- pr_debug("aio_run %ld\n", aio_run);
- pr_debug("aio_wakeups %ld\n", aio_wakeups);
return i ? i : ret;
}
@@ -1515,8 +1491,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
}
req->ki_filp = file;
- iocb->aio_key = req->ki_key;
- ret = put_user(iocb->aio_key, &user_iocb->aio_key);
+ ret = put_user(req->ki_key, &user_iocb->aio_key);
if (unlikely(ret)) {
dprintk("EFAULT: aio_key\n");
goto out_put_req;
@@ -1531,13 +1506,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
req->ki_opcode = iocb->aio_lio_opcode;
init_waitqueue_func_entry(&req->ki_wait, aio_wake_function);
INIT_LIST_HEAD(&req->ki_wait.task_list);
- req->ki_run_list.next = req->ki_run_list.prev = NULL;
- req->ki_retry = NULL;
req->ki_retried = 0;
- req->ki_kicked = 0;
- req->ki_queued = 0;
- aio_run = 0;
- aio_wakeups = 0;
ret = aio_setup_iocb(req);
@@ -1545,10 +1514,14 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
goto out_put_req;
spin_lock_irq(&ctx->ctx_lock);
- list_add_tail(&req->ki_run_list, &ctx->run_list);
- /* drain the run list */
- while (__aio_run_iocbs(ctx))
- ;
+ if (likely(list_empty(&ctx->run_list))) {
+ aio_run_iocb(req);
+ } else {
+ list_add_tail(&req->ki_run_list, &ctx->run_list);
+ /* drain the run list */
+ while (__aio_run_iocbs(ctx))
+ ;
+ }
spin_unlock_irq(&ctx->ctx_lock);
aio_put_req(req); /* drop extra ref to req */
return 0;
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index f5a52c871726..c7b2b8890188 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -84,6 +84,7 @@ struct autofs_wait_queue {
char *name;
/* This is for status reporting upon return */
int status;
+ atomic_t notified;
atomic_t wait_ctr;
};
@@ -101,6 +102,7 @@ struct autofs_sb_info {
int needs_reghost;
struct super_block *sb;
struct semaphore wq_sem;
+ spinlock_t fs_lock;
struct autofs_wait_queue *queues; /* Wait queue pointer */
};
@@ -126,9 +128,18 @@ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) {
static inline int autofs4_ispending(struct dentry *dentry)
{
struct autofs_info *inf = autofs4_dentry_ino(dentry);
+ int pending = 0;
- return (dentry->d_flags & DCACHE_AUTOFS_PENDING) ||
- (inf != NULL && inf->flags & AUTOFS_INF_EXPIRING);
+ if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
+ return 1;
+
+ if (inf) {
+ spin_lock(&inf->sbi->fs_lock);
+ pending = inf->flags & AUTOFS_INF_EXPIRING;
+ spin_unlock(&inf->sbi->fs_lock);
+ }
+
+ return pending;
}
static inline void autofs4_copy_atime(struct file *src, struct file *dst)
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 31540a6404d9..500425e24fba 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfsmount *mnt,
if (!autofs4_can_expire(top, timeout, do_now))
return 0;
+ /* Is someone visiting anywhere in the tree ? */
+ if (may_umount_tree(mnt))
+ return 0;
+
spin_lock(&dcache_lock);
repeat:
next = this_parent->d_subdirs.next;
@@ -270,10 +274,18 @@ static struct dentry *autofs4_expire(struct super_block *sb,
/* Case 2: tree mount, expire iff entire tree is not busy */
if (!exp_leaves) {
+ /* Lock the tree as we must expire as a whole */
+ spin_lock(&sbi->fs_lock);
if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
- expired = dentry;
- break;
+ struct autofs_info *inf = autofs4_dentry_ino(dentry);
+
+ /* Set this flag early to catch sys_chdir and the like */
+ inf->flags |= AUTOFS_INF_EXPIRING;
+ spin_unlock(&sbi->fs_lock);
+ expired = dentry;
+ break;
}
+ spin_unlock(&sbi->fs_lock);
/* Case 3: direct mount, expire individual leaves */
} else {
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index a52560746628..4bb14cc68040 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
sbi->version = 0;
sbi->sub_version = 0;
init_MUTEX(&sbi->wq_sem);
+ spin_lock_init(&sbi->fs_lock);
sbi->queues = NULL;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 1ab24a662e09..5a40d36e5a51 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -210,17 +210,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
wq->len = len;
wq->status = -EINTR; /* Status return if interrupted */
atomic_set(&wq->wait_ctr, 2);
+ atomic_set(&wq->notified, 1);
up(&sbi->wq_sem);
-
- DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d",
- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
- /* autofs4_notify_daemon() may block */
- if (notify != NFY_NONE) {
- autofs4_notify_daemon(sbi,wq,
- notify == NFY_MOUNT ?
- autofs_ptype_missing :
- autofs_ptype_expire_multi);
- }
} else {
atomic_inc(&wq->wait_ctr);
up(&sbi->wq_sem);
@@ -229,6 +220,17 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
}
+ if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) {
+ int type = (notify == NFY_MOUNT ?
+ autofs_ptype_missing : autofs_ptype_expire_multi);
+
+ DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+ (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify));
+
+ /* autofs4_notify_daemon() may block */
+ autofs4_notify_daemon(sbi, wq, type);
+ }
+
/* wq->name is NULL if and only if the lock is already released */
if ( sbi->catatonic ) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 6ae62cbf7c2e..ce9423bb2de3 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -945,7 +945,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = arch_setup_additional_pages(bprm, executable_stack);
if (retval < 0) {
send_sig(SIGKILL, current, 0);
- goto out_free_dentry;
+ goto out;
}
#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
diff --git a/fs/bio.c b/fs/bio.c
index e5349e834563..3a1472acc361 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -140,6 +140,7 @@ inline void bio_init(struct bio *bio)
* bio_alloc_bioset - allocate a bio for I/O
* @gfp_mask: the GFP_ mask given to the slab allocator
* @nr_iovecs: number of iovecs to pre-allocate
+ * @bs: the bio_set to allocate from
*
* Description:
* bio_alloc_bioset will first try it's on mempool to satisfy the allocation.
@@ -629,6 +630,7 @@ out:
/**
* bio_map_user - map user address into bio
+ * @q: the request_queue_t for the bio
* @bdev: destination block device
* @uaddr: start of user address
* @len: length in bytes
diff --git a/fs/buffer.c b/fs/buffer.c
index 3b12cf947aba..5f525b3c6d9f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -218,7 +218,7 @@ struct super_block *freeze_bdev(struct block_device *bdev)
sb = get_super(bdev);
if (sb && !(sb->s_flags & MS_RDONLY)) {
sb->s_frozen = SB_FREEZE_WRITE;
- wmb();
+ smp_wmb();
sync_inodes_sb(sb, 0);
DQUOT_SYNC(sb);
@@ -235,7 +235,7 @@ struct super_block *freeze_bdev(struct block_device *bdev)
sync_inodes_sb(sb, 1);
sb->s_frozen = SB_FREEZE_TRANS;
- wmb();
+ smp_wmb();
sync_blockdev(sb->s_bdev);
@@ -263,7 +263,7 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb)
if (sb->s_op->unlockfs)
sb->s_op->unlockfs(sb);
sb->s_frozen = SB_UNFROZEN;
- wmb();
+ smp_wmb();
wake_up(&sb->s_wait_unfrozen);
drop_super(sb);
}
@@ -774,15 +774,14 @@ repeat:
/**
* sync_mapping_buffers - write out and wait upon a mapping's "associated"
* buffers
- * @buffer_mapping - the mapping which backs the buffers' data
- * @mapping - the mapping which wants those buffers written
+ * @mapping: the mapping which wants those buffers written
*
* Starts I/O against the buffers at mapping->private_list, and waits upon
* that I/O.
*
- * Basically, this is a convenience function for fsync(). @buffer_mapping is
- * the blockdev which "owns" the buffers and @mapping is a file or directory
- * which needs those buffers to be written for a successful fsync().
+ * Basically, this is a convenience function for fsync().
+ * @mapping is a file or directory which needs those buffers to be written for
+ * a successful fsync().
*/
int sync_mapping_buffers(struct address_space *mapping)
{
@@ -1263,6 +1262,7 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
/**
* mark_buffer_dirty - mark a buffer_head as needing writeout
+ * @bh: the buffer_head to mark dirty
*
* mark_buffer_dirty() will set the dirty bit against the buffer, then set its
* backing page dirty, then tag the page as dirty in its address_space's radix
@@ -1501,6 +1501,7 @@ EXPORT_SYMBOL(__breadahead);
/**
* __bread() - reads a specified block and returns the bh
+ * @bdev: the block_device to read from
* @block: number of block
* @size: size (in bytes) to read
*
@@ -2078,8 +2079,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
int nr, i;
int fully_mapped = 1;
- if (!PageLocked(page))
- PAGE_BUG(page);
+ BUG_ON(!PageLocked(page));
blocksize = 1 << inode->i_blkbits;
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
@@ -2917,7 +2917,7 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
bh = head;
do {
- if (buffer_write_io_error(bh))
+ if (buffer_write_io_error(bh) && page->mapping)
set_bit(AS_EIO, &page->mapping->flags);
if (buffer_busy(bh))
goto failed;
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index acce36e25d2e..72fdc10dfdd7 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -4,13 +4,16 @@ Steve French (sfrench@samba.org)
The author wishes to express his appreciation and thanks to:
Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
-improvements. Thanks to IBM for allowing me the time and test resources to pursue
-this project. Jim McDonough from IBM (and the Samba Team) for his help.
-The IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+improvements. Thanks to IBM for allowing me time and test resources to pursue
+this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
+the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+Jeremy Allison of the Samba team has done invaluable work in adding the server
+side of the original CIFS Unix extensions and reviewing and implementing
+portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank
Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
-for proving years ago that a very good smb/cifs client could be done on a Unix like
-operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin
-and others for their work on the Linux smbfs module over the years. Thanks to
+for proving years ago that very good smb/cifs clients could be done on Unix-like
+operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John
+Newbigin and others for their work on the Linux smbfs module. Thanks to
the other members of the Storage Network Industry Association CIFS Technical
Workgroup for their work specifying this highly complex protocol and finally
thanks to the Samba team for their technical advice and encouragement.
@@ -24,9 +27,11 @@ Shobhit Dayal
Sergey Vlasov
Richard Hughes
Yury Umanets
-Mark Hamzy
+Mark Hamzy (for some of the early cifs IPv6 work)
Domen Puncer
-Jesper Juhl
+Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
+Vince Negri and Dave Stahl (for finding an important caching bug)
+Adrian Bunk (kcalloc cleanups)
Test case and Bug Report contributors
-------------------------------------
@@ -36,7 +41,8 @@ Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special
mention to the Stanford Checker (SWAT) which pointed out many minor
-bugs in error paths.
+bugs in error paths. Valuable suggestions also have come from Al Viro
+and Dave Miller.
And thanks to the IBM LTC and Power test teams and SuSE testers for
finding multiple bugs during excellent stress test runs.
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 5316c8dd6bff..95483baab706 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,7 +1,44 @@
-Version 1.31
+Version 1.34
+------------
+Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
+Do not oops if root user kills cifs oplock kernel thread or
+kills the cifsd thread (NB: killing the cifs kernel threads is not
+recommended, unmount and rmmod cifs will kill them when they are
+no longer needed). Fix readdir to ASCII servers (ie older servers
+which do not support Unicode) and also require asterik.
+
+
+Version 1.33
+------------
+Fix caching problem, in which readdir of directory containing a file
+which was cached could cause the file's time stamp to be updated
+without invalidating the readahead data (so we could get stale
+file data on the client for that file even as the server copy changed).
+Cleanup response processing so cifsd can not loop when abnormally
+terminated.
+
+
+Version 1.32
------------
Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
transact response for an SMB request and search entry split across two frames.
+Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
+as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
+unless server explicitly claims to support them in CIFS Unix extensions
+POSIX ACL capability bit. Fix packet signing when multiuser mounting with
+different users from the same client to the same server. Fix oops in
+cifs_close. Add mount option for remapping reserved characters in
+filenames (also allow recognizing files with created by SFU which have any
+of these seven reserved characters, except backslash, to be recognized).
+Fix invalid transact2 message (we were sometimes trying to interpret
+oplock breaks as SMB responses). Add ioctl for checking that the
+current uid matches the uid of the mounter (needed by umount.cifs).
+Reduce the number of large buffer allocations in cifs response processing
+(significantly reduces memory pressure under heavy stress with multiple
+processes accessing the same server at the same time).
+
+Version 1.31
+------------
Fix updates of DOS attributes and time fields so that files on NT4 servers
do not get marked delete on close. Display sizes of cifs buffer pools in
cifs stats. Fix oops in unmount when cifsd thread being killed by
diff --git a/fs/cifs/README b/fs/cifs/README
index 0f20edc935b5..7b4ac096cd11 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -75,7 +75,7 @@ Allowing User Mounts
====================
To permit users to mount and unmount over directories they own is possible
with the cifs vfs. A way to enable such mounting is to mark the mount.cifs
-utility as suid (e.g. "chmod +s /sbin/mount/cifs). To enable users to
+utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to
umount shares they mount requires
1) mount.cifs version 1.4 or later
2) an entry for the share in /etc/fstab indicating that a user may
@@ -97,6 +97,26 @@ mount.cifs with the following flag:
There is a corresponding manual page for cifs mounting in the Samba 3.0 and
later source tree in docs/manpages/mount.cifs.8
+Allowing User Unmounts
+======================
+To permit users to ummount directories that they have user mounted (see above),
+the utility umount.cifs may be used. It may be invoked directly, or if
+umount.cifs is placed in /sbin, umount can invoke the cifs umount helper
+(at least for most versions of the umount utility) for umount of cifs
+mounts, unless umount is invoked with -i (which will avoid invoking a umount
+helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked
+as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions
+allow adding entries to a file to the /etc/permissions file to achieve the
+equivalent suid effect). For this utility to succeed the target path
+must be a cifs mount, and the uid of the current user must match the uid
+of the user who mounted the resource.
+
+Also note that the customary way of allowing user mounts and unmounts is
+(instead of using mount.cifs and unmount.cifs as suid) to add a line
+to the file /etc/fstab for each //server/share you wish to mount, but
+this can become unwieldy when potential mount targets include many
+or unpredictable UNC names.
+
Samba Considerations
====================
To get the maximum benefit from the CIFS VFS, we recommend using a server that
@@ -376,6 +396,19 @@ A partial list of the supported mount options follows:
attributes) to the server (default) e.g. via setfattr
and getfattr utilities.
nouser_xattr Do not allow getfattr/setfattr to get/set xattrs
+ mapchars Translate six of the seven reserved characters (not backslash)
+ *?<>|:
+ to the remap range (above 0xF000), which also
+ allows the CIFS client to recognize files created with
+ such characters by Windows's POSIX emulation. This can
+ also be useful when mounting to most versions of Samba
+ (which also forbids creating and opening files
+ whose names contain any of these seven characters).
+ This has no effect if the server does not support
+ Unicode on the wire.
+ nomapchars Do not translate any of these seven characters (default).
+ remount remount the share (often used to change from ro to rw mounts
+ or vice versa)
The mount.cifs mount helper also accepts a few mount options before -o
including:
@@ -392,7 +425,7 @@ Misc /proc/fs/cifs Flags and Debug Info
=======================================
Informational pseudo-files:
DebugData Displays information about active CIFS sessions
- and shares.
+ and shares, as well as the cifs.ko version.
Stats Lists summary resource usage information as well as per
share statistics, if CONFIG_CIFS_STATS in enabled
in the kernel configuration.
@@ -449,7 +482,7 @@ and for more extensive tracing including the start of smb requests and responses
Two other experimental features are under development and to test
require enabling CONFIG_CIFS_EXPERIMENTAL
- More efficient write operations and SMB buffer handling
+ More efficient write operations
DNOTIFY fcntl: needed for support of directory change
notification and perhaps later for file leases)
@@ -467,8 +500,8 @@ returned success.
Also note that "cat /proc/fs/cifs/DebugData" will display information about
the active sessions and the shares that are mounted. Note: NTLMv2 enablement
-will not work since they its implementation is not quite complete yet.
-Do not alter these configuration values unless you are doing specific testing.
+will not work since its implementation is not quite complete yet. Do not alter
+the ExtendedSecurity configuration value unless you are doing specific testing.
Enabling extended security works to Windows 2000 Workstations and XP but not to
Windows 2000 server or Samba since it does not usually send "raw NTLMSSP"
(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index f4e3e1f67ee4..8cc881694e29 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-version 1.22 July 30, 2004
+version 1.34 April 29, 2005
A Partial List of Missing Features
==================================
@@ -14,7 +14,7 @@ b) Better pam/winbind integration (e.g. to handle uid mapping
better)
c) multi-user mounts - multiplexed sessionsetups over single vc
-(ie tcp session) - prettying up needed, and more testing needed
+(ie tcp session) - more testing needed
d) Kerberos/SPNEGO session setup support - (started)
@@ -67,12 +67,26 @@ q) implement support for security and trusted categories of xattrs
r) Implement O_DIRECT flag on open (already supported on mount)
-KNOWN BUGS (updated December 10, 2004)
+s) Allow remapping of last remaining character (\) to +0xF000 which
+(this character is valid for POSIX but not for Windows)
+
+t) Create UID mapping facility so server UIDs can be mapped on a per
+mount or a per server basis to client UIDs or nobody if no mapping
+exists. This is helpful when Unix extensions are negotiated to
+allow better permission checking when UIDs differ on the server
+and client. Add new protocol request to the CIFS protocol
+standard for asking the server for the corresponding name of a
+particular uid.
+
+KNOWN BUGS (updated April 29, 2005)
====================================
+See http://bugzilla.samba.org - search on product "CifsVFS" for
+current bug list.
+
1) existing symbolic links (Windows reparse points) are recognized but
can not be created remotely. They are implemented for Samba and those that
-support the CIFS Unix extensions but Samba has a bug currently handling
-symlink text beginning with slash
+support the CIFS Unix extensions, although earlier versions of Samba
+overly restrict the pathnames.
2) follow_link and readdir code does not follow dfs junctions
but recognizes them
3) create of new files to FAT partitions on Windows servers can
@@ -98,7 +112,5 @@ there are some easy changes that can be done to parallelize sequential writes,
and when signing is disabled to request larger read sizes (larger than
negotiated size) and send larger write sizes to modern servers.
-4) More exhaustively test the recently added NT4 support against various
-NT4 service pack levels, and fix cifs_setattr for setting file times and
-size to fall back to level 1 when error invalid level returned.
-
+4) More exhaustively test against less common servers. More testing
+against Windows 9x, Windows ME servers.
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index db28b561cd4b..4061e43471c1 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -1,7 +1,7 @@
/*
* fs/cifs_debug.c
*
- * Copyright (C) International Business Machines Corp., 2000,2003
+ * Copyright (C) International Business Machines Corp., 2000,2005
*
* Modified by Steve French (sfrench@us.ibm.com)
*
@@ -29,6 +29,7 @@
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
+#include "cifsfs.h"
void
cifs_dump_mem(char *label, void *data, int length)
@@ -78,8 +79,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
"Display Internal CIFS Data Structures for Debugging\n"
"---------------------------------------------------\n");
buf += length;
-
- length = sprintf(buf, "Servers:\n");
+ length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
+ buf += length;
+ length = sprintf(buf, "Servers:");
buf += length;
i = 0;
@@ -87,12 +89,21 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
list_for_each(tmp, &GlobalSMBSessionList) {
i++;
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
- length =
- sprintf(buf,
- "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t",
- i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
- ses->serverOS, ses->serverNOS, ses->capabilities,ses->status);
- buf += length;
+ if((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
+ (ses->serverNOS == NULL)) {
+ buf += sprintf("\nentry for %s not fully displayed\n\t",
+ ses->serverName);
+
+ } else {
+ length =
+ sprintf(buf,
+ "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t",
+ i, ses->serverName, ses->serverDomain,
+ atomic_read(&ses->inUse),
+ ses->serverOS, ses->serverNOS,
+ ses->capabilities,ses->status);
+ buf += length;
+ }
if(ses->server) {
buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
ses->server->tcpStatus,
@@ -100,7 +111,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses->server->secMode,
atomic_read(&ses->server->inFlight));
- length = sprintf(buf, "\nMIDs: \n");
+ length = sprintf(buf, "\nMIDs:\n");
buf += length;
spin_lock(&GlobalMid_Lock);
@@ -109,7 +120,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
mid_q_entry,
qhead);
if(mid_entry) {
- length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid);
+ length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",
+ mid_entry->midState,
+ (int)mid_entry->command,
+ mid_entry->pid,
+ mid_entry->tsk,
+ mid_entry->mid);
buf += length;
}
}
@@ -121,7 +137,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
sprintf(buf, "\n");
buf++;
- length = sprintf(buf, "\nShares:\n");
+ length = sprintf(buf, "Shares:");
buf += length;
i = 0;
@@ -200,7 +216,8 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
buf += item_length;
item_length =
sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n",
- bufAllocCount.counter,cifs_min_rcv + tcpSesAllocCount.counter);
+ bufAllocCount.counter,
+ cifs_min_rcv + tcpSesAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 77da902d8f32..ec00d61d5308 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -23,6 +23,7 @@
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
+#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index a17adf4cb9ba..99a096d3f84d 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -76,8 +76,8 @@ cifs_strtoUCS(wchar_t * to, const char *from, int len,
charlen));
to[i] = cpu_to_le16(0x003f); /* a question mark */
charlen = 1;
- }
- to[i] = cpu_to_le16(to[i]);
+ } else
+ to[i] = cpu_to_le16(to[i]);
}
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 78829e7d8cd0..1959c7c4b185 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char
return 0;
}
-int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
__u32 * pexpected_response_sequence_number)
{
int rc = 0;
@@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
/* BB remember to add code to save expected sequence number in midQ entry BB */
- if((cifs_pdu == NULL) || (ses == NULL))
+ if((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;
if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc;
spin_lock(&GlobalMid_Lock);
- cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
+ cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
- *pexpected_response_sequence_number = ses->sequence_number++;
- ses->sequence_number++;
+ *pexpected_response_sequence_number = server->sequence_number++;
+ server->sequence_number++;
spin_unlock(&GlobalMid_Lock);
- rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+ rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
if(rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else
@@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
hmac_md5_update((const unsigned char *) unicode_buf,
(user_name_len+dom_name_len)*2,&ctx);
- hmac_md5_final(ses->mac_signing_key,&ctx);
+ hmac_md5_final(ses->server->mac_signing_key,&ctx);
kfree(ucase_buf);
kfree(unicode_buf);
return 0;
@@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon
struct HMACMD5Context context;
memcpy(v2_session_response + 8, ses->server->cryptKey,8);
/* gen_blob(v2_session_response + 16); */
- hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
+ hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
hmac_md5_update(ses->server->cryptKey,8,&context);
/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 5082fce3c566..8cc23e7d0d5d 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -169,7 +169,8 @@ cifs_put_super(struct super_block *sb)
static int
cifs_statfs(struct super_block *sb, struct kstatfs *buf)
{
- int xid, rc = -EOPNOTSUPP;
+ int xid;
+ int rc = -EOPNOTSUPP;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
@@ -181,31 +182,34 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
buf->f_type = CIFS_MAGIC_NUMBER;
/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
- buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably
- be length of total path, note that some servers may be
- able to support more than this, but best to be safe
- since Win2k and others can not handle very long filenames */
+ buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
+ presumably be total path, but note
+ that some servers (includinng Samba 3)
+ have a shorter maximum path */
buf->f_files = 0; /* undefined */
buf->f_ffree = 0; /* unlimited */
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB we could add a second check for a QFS Unix capability bit */
- if (pTcon->ses->capabilities & CAP_UNIX)
- rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf, cifs_sb->local_nls);
+/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
+ if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
+ le64_to_cpu(pTcon->fsUnixInfo.Capability)))
+ rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
/* Only need to call the old QFSInfo if failed
on newer one */
if(rc)
#endif /* CIFS_EXPERIMENTAL */
- rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
+ rc = CIFSSMBQFSInfo(xid, pTcon, buf);
/*
int f_type;
__fsid_t f_fsid;
int f_namelen; */
- /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
+ /* BB get from info in tcon struct at mount time call to QFSAttrInfo */
FreeXid(xid);
- return 0; /* always return success? what if volume is no longer available? */
+ return 0; /* always return success? what if volume is no
+ longer available? */
}
static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
@@ -559,6 +563,10 @@ struct file_operations cifs_file_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.sendfile = generic_file_sendfile,
+#ifdef CONFIG_CIFS_POSIX
+ .ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
#ifdef CONFIG_CIFS_EXPERIMENTAL
.readv = generic_file_readv,
.writev = generic_file_writev,
@@ -579,6 +587,10 @@ struct file_operations cifs_file_direct_ops = {
.fsync = cifs_fsync,
.flush = cifs_flush,
.sendfile = generic_file_sendfile, /* BB removeme BB */
+#ifdef CONFIG_CIFS_POSIX
+ .ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
@@ -591,6 +603,7 @@ struct file_operations cifs_dir_ops = {
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
+ .ioctl = cifs_ioctl,
};
static void
@@ -822,6 +835,7 @@ static int cifs_oplock_thread(void * dummyarg)
}
} while(!signal_pending(current));
complete_and_exit (&cifs_oplock_exited, 0);
+ oplockThread = NULL;
}
static int __init
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 451f18af3206..d00b3bfe1a52 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsfs.h
*
- * Copyright (c) International Business Machines Corp., 2002
+ * Copyright (c) International Business Machines Corp., 2002, 2005
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -91,8 +91,10 @@ extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname);
extern int cifs_removexattr(struct dentry *, const char *);
extern int cifs_setxattr(struct dentry *, const char *, const void *,
- size_t, int);
+ size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
-#define CIFS_VERSION "1.31"
+extern int cifs_ioctl (struct inode * inode, struct file * filep,
+ unsigned int command, unsigned long arg);
+#define CIFS_VERSION "1.34"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 69aff1a7da9b..81babab265e1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsglob.h
*
- * Copyright (C) International Business Machines Corp., 2002,2003
+ * Copyright (C) International Business Machines Corp., 2002,2005
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -149,6 +149,8 @@ struct TCP_Server_Info {
__u16 timeZone;
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+ __u32 sequence_number; /* needed for CIFS PDU signature */
+ char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
};
/*
@@ -174,17 +176,16 @@ struct cifsSesInfo {
struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of mounts (tree connections) on this ses */
enum statusEnum status;
- __u32 sequence_number; /* needed for CIFS PDU signature */
__u16 ipc_tid; /* special tid for connection to IPC share */
__u16 flags;
- char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
- char *serverOS; /* name of operating system underlying the server */
- char *serverNOS; /* name of network operating system that the server is running */
+ char *serverOS; /* name of operating system underlying server */
+ char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */
int Suid; /* remote smb uid */
uid_t linux_uid; /* local Linux uid */
int capabilities;
- char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
+ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
+ TCP names - will ipv6 and sctp addresses fit? */
char userName[MAX_USERNAME_SIZE + 1];
char domainName[MAX_USERNAME_SIZE + 1];
char * password;
@@ -312,12 +313,15 @@ struct mid_q_entry {
__u16 mid; /* multiplex id */
__u16 pid; /* process id */
__u32 sequence_number; /* for CIFS signing */
- __u16 command; /* smb command code */
struct timeval when_sent; /* time when smb sent */
struct cifsSesInfo *ses; /* smb was sent to this server */
struct task_struct *tsk; /* task waiting for response */
struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this were enum but can not pass to wait_event */
+ __u8 command; /* smb command code */
+ unsigned multiPart:1; /* multiple responses to one SMB request */
+ unsigned largeBuf:1; /* if valid response, is pointer to large buf */
+ unsigned multiResp:1; /* multiple trans2 responses for one request */
};
struct oplock_q_entry {
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index bcd4a6136f08..aede6a813167 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -330,7 +330,7 @@ struct smb_hdr {
};
/* given a pointer to an smb_hdr retrieve the value of byte count */
#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
-
+#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
@@ -762,6 +762,16 @@ typedef struct smb_com_lock_req {
LOCKING_ANDX_RANGE Locks[1];
} LOCK_REQ;
+
+typedef struct cifs_posix_lock {
+ __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */
+ __le16 lock_flags; /* 1 = Wait (only valid for setlock) */
+ __le32 pid;
+ __le64 start;
+ __le64 length;
+ /* BB what about additional owner info to identify network client */
+} CIFS_POSIX_LOCK;
+
typedef struct smb_com_lock_rsp {
struct smb_hdr hdr; /* wct = 2 */
__u8 AndXCommand;
@@ -1098,6 +1108,8 @@ struct smb_t2_rsp {
#define SMB_QUERY_POSIX_ACL 0x204
#define SMB_QUERY_XATTR 0x205
#define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */
+#define SMB_QUERY_POSIX_PERMISSION 0x207
+#define SMB_QUERY_POSIX_LOCK 0x208
#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
@@ -1116,6 +1128,7 @@ struct smb_t2_rsp {
#define SMB_SET_POSIX_ACL 0x204
#define SMB_SET_XATTR 0x205
#define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
+#define SMB_SET_POSIX_LOCK 0x208
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
#define SMB_FILE_ALL_INFO2 0x3fa
@@ -1237,9 +1250,25 @@ struct smb_com_transaction2_sfi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2;
__u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
+ __u16 Reserved2; /* parameter word reserved -
+ present for infolevels > 100 */
+};
+
+struct smb_t2_qfi_req {
+ struct smb_hdr hdr;
+ struct trans2_req t2;
+ __u8 Pad;
+ __u16 Fid;
+ __le16 InformationLevel;
};
+struct smb_t2_qfi_rsp {
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved -
+ present for infolevels > 100 */
+};
/*
* Flags on T2 FINDFIRST and FINDNEXT
@@ -1524,9 +1553,10 @@ typedef struct {
} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */
/* Linux/Unix extensions capability flags */
#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
-#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002
-#define CIFS_UNIX_XATTR_CAP 0x00000004 /*support for new namespace*/
-
+#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */
+#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */
+#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */
+#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */
typedef struct {
/* For undefined recommended transfer size return -1 in that field */
__le32 OptimalTransferSize; /* bsize on some os, iosize on other os */
@@ -1971,14 +2001,39 @@ struct xsymlink {
char path[1024];
};
-typedef struct {
+typedef struct file_xattr_info {
/* BB do we need another field for flags? BB */
__u32 xattr_name_len;
__u32 xattr_value_len;
char xattr_name[0];
/* followed by xattr_value[xattr_value_len], no pad */
-} FILE_XATTR_INFO; /* extended attribute, info level 205 */
-
+} FILE_XATTR_INFO; /* extended attribute, info level 0x205 */
+
+
+/* flags for chattr command */
+#define EXT_SECURE_DELETE 0x00000001 /* EXT3_SECRM_FL */
+#define EXT_ENABLE_UNDELETE 0x00000002 /* EXT3_UNRM_FL */
+/* Reserved for compress file 0x4 */
+#define EXT_SYNCHRONOUS 0x00000008 /* EXT3_SYNC_FL */
+#define EXT_IMMUTABLE_FL 0x00000010 /* EXT3_IMMUTABLE_FL */
+#define EXT_OPEN_APPEND_ONLY 0x00000020 /* EXT3_APPEND_FL */
+#define EXT_DO_NOT_BACKUP 0x00000040 /* EXT3_NODUMP_FL */
+#define EXT_NO_UPDATE_ATIME 0x00000080 /* EXT3_NOATIME_FL */
+/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
+#define EXT_HASH_TREE_INDEXED_DIR 0x00001000 /* GET-ONLY EXT3_INDEX_FL */
+/* 0x2000 reserved for IMAGIC_FL */
+#define EXT_JOURNAL_THIS_FILE 0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
+/* 0x8000 reserved for EXT3_NOTAIL_FL */
+#define EXT_SYNCHRONOUS_DIR 0x00010000 /* EXT3_DIRSYNC_FL */
+#define EXT_TOPDIR 0x00020000 /* EXT3_TOPDIR_FL */
+
+#define EXT_SET_MASK 0x000300FF
+#define EXT_GET_MASK 0x0003DFFF
+
+typedef struct file_chattr_info {
+ __le64 mask; /* list of all possible attribute bits */
+ __le64 mode; /* list of actual attribute bits on this inode */
+} FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */
#endif
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 787eef4d86d3..0010511083fc 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -57,10 +57,11 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length,
extern int cifs_inet_pton(int, char * source, void *dst);
extern int map_smb_to_linux_error(struct smb_hdr *smb);
extern void header_assemble(struct smb_hdr *, char /* command */ ,
- const struct cifsTconInfo *, int
- /* length of fixed section (word count) in two byte units */
+ const struct cifsTconInfo *, int /* specifies length
+ of fixed section (word count) in two byte units */
);
-extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *);
+extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
+ struct cifsTconInfo *);
extern void DeleteOplockQEntry(struct oplock_q_entry *);
extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
extern u64 cifs_UnixTimeToNT(struct timespec);
@@ -88,7 +89,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
const char *searchName, const struct nls_table *nls_codepage,
- __u16 *searchHandle, struct cifs_search_info * psrch_inf);
+ __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map);
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
__u16 searchHandle, struct cifs_search_info * psrch_inf);
@@ -99,42 +100,42 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * findData,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBUnixQPathInfo(const int xid,
struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_UNIX_BASIC_INFO * pFindData,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
unsigned char **targetUNCs,
unsigned int *number_of_UNC_in_array,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap);
extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- const char *old_path, const struct nls_table *nls_codepage,
- unsigned int *pnum_referrals, unsigned char ** preferrals);
+ const char *old_path,
+ const struct nls_table *nls_codepage,
+ unsigned int *pnum_referrals,
+ unsigned char ** preferrals,
+ int remap);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
- struct kstatfs *FSData,
- const struct nls_table *nls_codepage);
+ struct kstatfs *FSData);
extern int CIFSSMBQFSAttributeInfo(const int xid,
- struct cifsTconInfo *tcon,
- const struct nls_table *nls_codepage);
-extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
- const struct nls_table *nls_codepage);
-extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
- const struct nls_table *nls_codepage);
+ struct cifsTconInfo *tcon);
+extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
- struct kstatfs *FSData, const struct nls_table *nls_codepage);
+ struct kstatfs *FSData);
extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const FILE_BASIC_INFO * data,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
const FILE_BASIC_INFO * data, __u16 fid);
#if 0
@@ -143,36 +144,49 @@ extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage);
#endif /* possibly unneeded function */
extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
- const char *fileName, __u64 size,int setAllocationSizeFlag,
- const struct nls_table *nls_codepage);
+ const char *fileName, __u64 size,
+ int setAllocationSizeFlag,
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
- __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag);
+ __u64 size, __u16 fileHandle,__u32 opener_pid,
+ int AllocSizeFlag);
extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
char *full_path, __u64 mode, __u64 uid,
- __u64 gid, dev_t dev, const struct nls_table *nls_codepage);
+ __u64 gid, dev_t dev,
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
const char *newName,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
- const char *name, const struct nls_table *nls_codepage);
+ const char *name, const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
- int netfid, char * target_name, const struct nls_table *nls_codepage);
+ int netfid, char * target_name,
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSCreateHardLink(const int xid,
struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSUnixCreateHardLink(const int xid,
struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSUnixCreateSymLink(const int xid,
struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
@@ -192,7 +206,7 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id);
@@ -211,8 +225,13 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
const char __user *buf,const int long_op);
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, __u64 * inode_number,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
#endif /* CONFIG_CIFS_EXPERIMENTAL */
+extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen,
+ const struct nls_table * codepage);
+extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
+ const struct nls_table * cp, int mapChars);
extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 netfid, const __u64 len,
@@ -230,7 +249,7 @@ extern void tconInfoFree(struct cifsTconInfo *);
extern int cifs_reconnect(struct TCP_Server_Info *server);
-extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
__u32 expected_sequence_number);
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
@@ -241,29 +260,31 @@ extern int CIFSSMBCopy(int xid,
const char *fromName,
const __u16 target_tid,
const char *toName, const int flags,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
- const int notify_subdirs,const __u16 netfid,__u32 filter,
- const struct nls_table *nls_codepage);
+ const int notify_subdirs,const __u16 netfid,
+ __u32 filter, const struct nls_table *nls_codepage);
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, char * EAData,
- size_t bufsize, const struct nls_table *nls_codepage);
+ size_t bufsize, const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
const unsigned char * searchName,const unsigned char * ea_name,
unsigned char * ea_value, size_t buf_size,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const char * ea_name,
const void * ea_value, const __u16 ea_value_len,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *acl_inf, const int buflen,const int acl_type,
- const struct nls_table *nls_codepage);
+ const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *fileName,
const char *local_acl, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage);
-int cifs_ioctl (struct inode * inode, struct file * filep,
- unsigned int command, unsigned long arg);
+ const struct nls_table *nls_codepage, int remap_special_chars);
+extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+ const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
#endif /* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index df6a619a6821..741ff0c69f37 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -75,7 +75,8 @@ static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
}
}
write_unlock(&GlobalSMBSeslock);
- /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
+ /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
+ to this tcon */
}
/* If the return code is zero, this function must fill in request_buf pointer */
@@ -89,11 +90,12 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
check for tcp and smb session status done differently
for those three - in the calling routine */
if(tcon) {
- if((tcon->ses) && (tcon->ses->server)){
+ if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+ (tcon->ses->server)){
struct nls_table *nls_codepage;
/* Give Demultiplex thread up to 10 seconds to
- reconnect, should be greater than cifs socket
- timeout which is 7 seconds */
+ reconnect, should be greater than cifs socket
+ timeout which is 7 seconds */
while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
@@ -103,8 +105,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
(tcon->ses->status == CifsExiting)) {
cFYI(1,("gave up waiting on reconnect in smb_init"));
return -EHOSTDOWN;
- } /* else "hard" mount - keep retrying until
- process is killed or server comes back up */
+ } /* else "hard" mount - keep retrying
+ until process is killed or server
+ comes back on-line */
} else /* TCP session is reestablished now */
break;
@@ -115,23 +118,24 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
if(tcon->ses->status == CifsNeedReconnect)
- rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+ rc = cifs_setup_session(0, tcon->ses,
+ nls_codepage);
if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
mark_open_files_invalid(tcon);
- rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
- nls_codepage);
+ rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
+ , nls_codepage);
up(&tcon->ses->sesSem);
if(rc == 0)
atomic_inc(&tconInfoReconnectCount);
cFYI(1, ("reconnect tcon rc = %d", rc));
/* Removed call to reopen open files here -
- it is safer (and faster) to reopen files
- one at a time as needed in read and write */
+ it is safer (and faster) to reopen files
+ one at a time as needed in read and write */
/* Check if handle based operation so we
- know whether we can continue or not without
- returning to caller to reset file handle */
+ know whether we can continue or not without
+ returning to caller to reset file handle */
switch(smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
@@ -182,22 +186,25 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
check for tcp and smb session status done differently
for those three - in the calling routine */
if(tcon) {
- if((tcon->ses) && (tcon->ses->server)){
+ if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+ (tcon->ses->server)){
struct nls_table *nls_codepage;
- /* Give Demultiplex thread up to 10 seconds to
- reconnect, should be greater than cifs socket
- timeout which is 7 seconds */
+ /* Give Demultiplex thread up to 10 seconds to
+ reconnect, should be greater than cifs socket
+ timeout which is 7 seconds */
while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
- if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+ if(tcon->ses->server->tcpStatus ==
+ CifsNeedReconnect) {
/* on "soft" mounts we wait once */
if((tcon->retry == FALSE) ||
(tcon->ses->status == CifsExiting)) {
cFYI(1,("gave up waiting on reconnect in smb_init"));
return -EHOSTDOWN;
- } /* else "hard" mount - keep retrying until
- process is killed or server comes back up */
+ } /* else "hard" mount - keep retrying
+ until process is killed or server
+ comes on-line */
} else /* TCP session is reestablished now */
break;
@@ -208,23 +215,24 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
if(tcon->ses->status == CifsNeedReconnect)
- rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+ rc = cifs_setup_session(0, tcon->ses,
+ nls_codepage);
if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
mark_open_files_invalid(tcon);
- rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
- nls_codepage);
+ rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+ tcon, nls_codepage);
up(&tcon->ses->sesSem);
if(rc == 0)
atomic_inc(&tconInfoReconnectCount);
cFYI(1, ("reconnect tcon rc = %d", rc));
/* Removed call to reopen open files here -
- it is safer (and faster) to reopen files
- one at a time as needed in read and write */
+ it is safer (and faster) to reopen files
+ one at a time as needed in read and write */
/* Check if handle based operation so we
- know whether we can continue or not without
- returning to caller to reset file handle */
+ know whether we can continue or not without
+ returning to caller to reset file handle */
switch(smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
@@ -286,7 +294,8 @@ static int validate_t2(struct smb_t2_rsp * pSMB)
if(total_size < 512) {
total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
/* BCC le converted in SendReceive */
- pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) +
+ pBCC = (pSMB->hdr.WordCount * 2) +
+ sizeof(struct smb_hdr) +
(char *)pSMB;
if((total_size <= (*(u16 *)pBCC)) &&
(total_size <
@@ -337,8 +346,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc == 0) {
server->secMode = pSMBr->SecurityMode;
- server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
- /* one byte - no need to convert this or EncryptionKeyLen from le,*/
+ server->secType = NTLM; /* BB override default for
+ NTLMv2 or kerberos v5 */
+ /* one byte - no need to convert this or EncryptionKeyLen
+ from little endian */
server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
/* probably no need to store and check maxvcs */
server->maxBuf =
@@ -374,7 +385,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
pSMBr->u.extended_response.
GUID, 16) != 0) {
cFYI(1,
- ("UID of server does not match previous connection to same ip address"));
+ ("UID of server does not match previous connection to same ip address"));
memcpy(server->
server_GUID,
pSMBr->u.
@@ -454,17 +465,18 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
up(&tcon->tconSem);
return -EIO;
}
- rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer);
+ rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
+ (void **)&smb_buffer);
if (rc) {
up(&tcon->tconSem);
return rc;
} else {
smb_buffer_response = smb_buffer; /* BB removeme BB */
- }
+ }
rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
&length, 0);
if (rc)
- cFYI(1, (" Tree disconnect failed %d", rc));
+ cFYI(1, ("Tree disconnect failed %d", rc));
if (smb_buffer)
cifs_small_buf_release(smb_buffer);
@@ -538,8 +550,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
}
int
-CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
- const char *fileName, const struct nls_table *nls_codepage)
+CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+ const struct nls_table *nls_codepage, int remap)
{
DELETE_FILE_REQ *pSMB = NULL;
DELETE_FILE_RSP *pSMBr = NULL;
@@ -555,12 +567,11 @@ DelFileRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->fileName, fileName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve check for buffer overruns BB */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->fileName, fileName, name_len);
@@ -589,8 +600,8 @@ DelFileRetry:
}
int
-CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
- const char *dirName, const struct nls_table *nls_codepage)
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
+ const struct nls_table *nls_codepage, int remap)
{
DELETE_DIRECTORY_REQ *pSMB = NULL;
DELETE_DIRECTORY_RSP *pSMBr = NULL;
@@ -606,12 +617,11 @@ RmDirRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve check for buffer overruns BB */
name_len = strnlen(dirName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->DirName, dirName, name_len);
@@ -639,7 +649,7 @@ RmDirRetry:
int
CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
- const char *name, const struct nls_table *nls_codepage)
+ const char *name, const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
CREATE_DIRECTORY_REQ *pSMB = NULL;
@@ -655,12 +665,11 @@ MkDirRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ name_len = cifsConvertToUCS((__u16 *) pSMB->DirName, name,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve check for buffer overruns BB */
name_len = strnlen(name, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->DirName, name, name_len);
@@ -690,7 +699,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
const int access_flags, const int create_options, __u16 * netfid,
int *pOplock, FILE_ALL_INFO * pfile_info,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
int rc = -EACCES;
OPEN_REQ *pSMB = NULL;
@@ -710,14 +719,12 @@ openRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
count = 1; /* account for one byte pad to word boundary */
name_len =
- cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
- fileName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) (pSMB->fileName + 1),
+ fileName, PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->NameLength = cpu_to_le16(name_len);
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve check for buffer overruns BB */
count = 0; /* no pad */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
@@ -746,7 +753,8 @@ openRetry:
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(create_options);
- pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
+ /* BB Expirement with various impersonation levels and verify */
+ pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
pSMB->SecurityFlags =
SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
@@ -760,7 +768,7 @@ openRetry:
if (rc) {
cFYI(1, ("Error in Open = %d", rc));
} else {
- *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */
+ *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
*netfid = pSMBr->Fid; /* cifs fid stays in le */
/* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */
@@ -1017,11 +1025,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
__u16 count;
cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
- rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
+
if (rc)
return rc;
+ pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
+
if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
timeout = -1; /* no response expected */
pSMB->Timeout = 0;
@@ -1059,7 +1069,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
if (rc) {
cFYI(1, ("Send error in Lock = %d", rc));
}
- cifs_buf_release(pSMB);
+ cifs_small_buf_release(pSMB);
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
@@ -1108,7 +1118,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
int
CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
RENAME_REQ *pSMB = NULL;
@@ -1131,18 +1141,16 @@ renameRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 =
- cifs_strtoUCS((wchar_t *) & pSMB->
- OldFileName[name_len + 2], toName, PATH_MAX,
- nls_codepage);
+ cifsConvertToUCS((__u16 *) &pSMB->OldFileName[name_len + 2],
+ toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
@@ -1182,7 +1190,8 @@ renameRetry:
}
int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
- int netfid, char * target_name, const struct nls_table * nls_codepage)
+ int netfid, char * target_name,
+ const struct nls_table * nls_codepage, int remap)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -1227,9 +1236,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
/* unicode only call */
if(target_name == NULL) {
sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
- len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
+ len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name,
+ dummy_string, 24, nls_codepage, remap);
} else {
- len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage);
+ len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name,
+ target_name, PATH_MAX, nls_codepage, remap);
}
rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
@@ -1263,7 +1274,7 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
int
CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
const __u16 target_tid, const char *toName, const int flags,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
COPY_REQ *pSMB = NULL;
@@ -1285,18 +1296,16 @@ copyRetry:
pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName,
- fromName,
- PATH_MAX /* find define for this maxpathcomponent */,
- nls_codepage);
+ name_len = cifsConvertToUCS((__u16 *) pSMB->OldFileName,
+ fromName, PATH_MAX, nls_codepage,
+ remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00;
- name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
- OldFileName[name_len + 2], toName, PATH_MAX,
- nls_codepage);
+ name_len2 = cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2],
+ toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
@@ -1425,7 +1434,7 @@ createSymLinkRetry:
int
CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -1444,9 +1453,8 @@ createHardLinkRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ name_len = cifsConvertToUCS((__u16 *) pSMB->FileName, toName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -1468,9 +1476,8 @@ createHardLinkRetry:
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len_target =
- cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) data_offset, fromName, PATH_MAX,
+ nls_codepage, remap);
name_len_target++; /* trailing null */
name_len_target *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -1512,7 +1519,7 @@ createHardLinkRetry:
int
CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
NT_RENAME_REQ *pSMB = NULL;
@@ -1539,17 +1546,15 @@ winCreateHardLinkRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0; /* pad */
pSMB->OldFileName[name_len + 1] = 0x04;
name_len2 =
- cifs_strtoUCS((wchar_t *) & pSMB->
- OldFileName[name_len + 2], toName, PATH_MAX,
- nls_codepage);
+ cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2],
+ toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
@@ -1659,6 +1664,7 @@ querySymLinkRetry:
name_len = UniStrnlen((wchar_t *) ((char *)
&pSMBr->hdr.Protocol +data_offset),
min_t(const int, buflen,count) / 2);
+ /* BB FIXME investigate remapping reserved chars here */
cifs_strfromUCS_le(symlinkinfo,
(wchar_t *) ((char *)&pSMBr->hdr.Protocol +
data_offset),
@@ -1793,7 +1799,8 @@ static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace
}
/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
-static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area)
+static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
+ const int acl_type,const int size_of_data_area)
{
int size = 0;
int i;
@@ -1912,7 +1919,7 @@ int
CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *acl_inf, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
/* SMB_QUERY_POSIX_ACL */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -1932,8 +1939,8 @@ queryAclRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->FileName[name_len] = 0;
@@ -1997,8 +2004,9 @@ queryAclRetry:
int
CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *fileName,
- const char *local_acl, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage)
+ const char *local_acl, const int buflen,
+ const int acl_type,
+ const struct nls_table *nls_codepage, int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -2016,8 +2024,8 @@ setAclRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, fileName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -2072,13 +2080,96 @@ setACLerrorExit:
return rc;
}
-#endif
+/* BB fix tabs in this function FIXME BB */
+int
+CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+ const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+{
+ int rc = 0;
+ struct smb_t2_qfi_req *pSMB = NULL;
+ struct smb_t2_qfi_rsp *pSMBr = NULL;
+ int bytes_returned;
+ __u16 params, byte_count;
+
+ cFYI(1,("In GetExtAttr"));
+ if(tcon == NULL)
+ return -ENODEV;
+
+GetExtAttrRetry:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ params = 2 /* level */ +2 /* fid */;
+ pSMB->t2.TotalDataCount = 0;
+ pSMB->t2.MaxParameterCount = cpu_to_le16(4);
+ /* BB find exact max data count below from sess structure BB */
+ pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+ pSMB->t2.MaxSetupCount = 0;
+ pSMB->t2.Reserved = 0;
+ pSMB->t2.Flags = 0;
+ pSMB->t2.Timeout = 0;
+ pSMB->t2.Reserved2 = 0;
+ pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+ Fid) - 4);
+ pSMB->t2.DataCount = 0;
+ pSMB->t2.DataOffset = 0;
+ pSMB->t2.SetupCount = 1;
+ pSMB->t2.Reserved3 = 0;
+ pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+ byte_count = params + 1 /* pad */ ;
+ pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+ pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+ pSMB->Pad = 0;
+ pSMB->Fid = netfid;
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->t2.ByteCount = cpu_to_le16(byte_count);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("error %d in GetExtAttr", rc));
+ } else {
+ /* decode response */
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+ if (rc || (pSMBr->ByteCount < 2))
+ /* BB also check enough total bytes returned */
+ /* If rc should we check for EOPNOSUPP and
+ disable the srvino flag? or in caller? */
+ rc = -EIO; /* bad smb */
+ else {
+ __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+ __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+ struct file_chattr_info * pfinfo;
+ /* BB Do we need a cast or hash here ? */
+ if(count != 16) {
+ cFYI(1, ("Illegal size ret in GetExtAttr"));
+ rc = -EIO;
+ goto GetExtAttrOut;
+ }
+ pfinfo = (struct file_chattr_info *)
+ (data_offset + (char *) &pSMBr->hdr.Protocol);
+ *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+ *pMask = le64_to_cpu(pfinfo->mask);
+ }
+ }
+GetExtAttrOut:
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto GetExtAttrRetry;
+ return rc;
+}
+
+
+#endif /* CONFIG_POSIX */
int
CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * pFindData,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
/* level 263 SMB_QUERY_FILE_ALL_INFO */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2097,9 +2188,8 @@ QPathInfoRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -2160,7 +2250,7 @@ int
CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_UNIX_BASIC_INFO * pFindData,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
/* SMB_QUERY_FILE_UNIX_BASIC */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2179,9 +2269,8 @@ UnixQPathInfoRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -2261,7 +2350,7 @@ findUniqueRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+ cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
/* find define for this maxpathcomponent */
, nls_codepage);
name_len++; /* trailing null */
@@ -2325,7 +2414,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
const char *searchName,
const struct nls_table *nls_codepage,
__u16 * pnetfid,
- struct cifs_search_info * psrch_inf)
+ struct cifs_search_info * psrch_inf, int remap)
{
/* level 257 SMB_ */
TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2336,7 +2425,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
int name_len;
__u16 params, byte_count;
- cFYI(1, ("In FindFirst"));
+ cFYI(1, ("In FindFirst for %s",searchName));
findFirstRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -2346,20 +2435,30 @@ findFirstRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName,
- PATH_MAX, nls_codepage);
- name_len++; /* trailing null */
+ cifsConvertToUCS((__u16 *) pSMB->FileName,searchName,
+ PATH_MAX, nls_codepage, remap);
+ /* We can not add the asterik earlier in case
+ it got remapped to 0xF03A as if it were part of the
+ directory name instead of a wildcard */
name_len *= 2;
+ pSMB->FileName[name_len] = '\\';
+ pSMB->FileName[name_len+1] = 0;
+ pSMB->FileName[name_len+2] = '*';
+ pSMB->FileName[name_len+3] = 0;
+ name_len += 4; /* now the trailing null */
pSMB->FileName[name_len] = 0; /* null terminate just in case */
pSMB->FileName[name_len+1] = 0;
+ name_len += 2;
} else { /* BB add check for overrun of SMB buf BB */
name_len = strnlen(searchName, PATH_MAX);
- name_len++; /* trailing null */
/* BB fix here and in unicode clause above ie
if(name_len > buffersize-header)
free buffer exit; BB */
strncpy(pSMB->FileName, searchName, name_len);
- pSMB->FileName[name_len] = 0; /* just in case */
+ pSMB->FileName[name_len] = '\\';
+ pSMB->FileName[name_len+1] = '*';
+ pSMB->FileName[name_len+2] = 0;
+ name_len += 3;
}
params = 12 + name_len /* includes null */ ;
@@ -2422,7 +2521,6 @@ findFirstRetry:
psrch_inf->srch_entries_start =
(char *) &pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.DataOffset);
-
parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.ParameterOffset));
@@ -2434,7 +2532,6 @@ findFirstRetry:
psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry =
psrch_inf->entries_in_buffer;
-/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
*pnetfid = parms->SearchHandle;
} else {
cifs_buf_release(pSMB);
@@ -2608,7 +2705,7 @@ int
CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
__u64 * inode_number,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2629,8 +2726,8 @@ GetInodeNumberRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName,
- PATH_MAX,nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, searchName,
+ PATH_MAX,nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -2704,7 +2801,7 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
unsigned char **targetUNCs,
unsigned int *number_of_UNC_in_array,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
/* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
@@ -2740,10 +2837,8 @@ getDFSRetry:
if (ses->capabilities & CAP_UNICODE) {
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
- searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->RequestFileName,
+ searchName, PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -2871,8 +2966,7 @@ GetDFSRefExit:
}
int
-CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
- struct kstatfs *FSData, const struct nls_table *nls_codepage)
+CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
{
/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -2955,8 +3049,7 @@ QFSInfoRetry:
}
int
-CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
- const struct nls_table *nls_codepage)
+CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
{
/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3024,8 +3117,7 @@ QFSAttributeRetry:
}
int
-CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
- const struct nls_table *nls_codepage)
+CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
{
/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3078,8 +3170,8 @@ QFSDeviceRetry:
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
response_data =
- (FILE_SYSTEM_DEVICE_INFO
- *) (((char *) &pSMBr->hdr.Protocol) +
+ (FILE_SYSTEM_DEVICE_INFO *)
+ (((char *) &pSMBr->hdr.Protocol) +
data_offset);
memcpy(&tcon->fsDevInfo, response_data,
sizeof (FILE_SYSTEM_DEVICE_INFO));
@@ -3094,8 +3186,7 @@ QFSDeviceRetry:
}
int
-CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
- const struct nls_table *nls_codepage)
+CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
{
/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3166,7 +3257,7 @@ QFSUnixRetry:
int
CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
- struct kstatfs *FSData, const struct nls_table *nls_codepage)
+ struct kstatfs *FSData)
{
/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3258,7 +3349,8 @@ QFSPosixRetry:
int
CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
+ __u64 size, int SetAllocation,
+ const struct nls_table *nls_codepage, int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -3277,9 +3369,8 @@ SetEOFRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, fileName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -3360,11 +3451,13 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
(long long)size));
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
if (rc)
return rc;
+ pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
@@ -3424,7 +3517,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
}
if (pSMB)
- cifs_buf_release(pSMB);
+ cifs_small_buf_release(pSMB);
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
@@ -3450,11 +3543,13 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
__u16 params, param_offset, offset, byte_count, count;
cFYI(1, ("Set Times (via SetFileInfo)"));
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
if (rc)
return rc;
+ pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
/* At this point there is no need to override the current pid
with the pid of the opener, but that could change if we someday
use an existing handle (rather than opening one on the fly) */
@@ -3500,7 +3595,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
}
- cifs_buf_release(pSMB);
+ cifs_small_buf_release(pSMB);
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
@@ -3512,7 +3607,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
int
CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
const FILE_BASIC_INFO * data,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -3532,9 +3627,8 @@ SetTimesRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, fileName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -3614,7 +3708,7 @@ SetAttrLgcyRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName,
+ ConvertToUCS((wchar_t *) pSMB->fileName, fileName,
PATH_MAX, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
@@ -3644,8 +3738,9 @@ SetAttrLgcyRetry:
int
CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
- char *fileName, __u64 mode, __u64 uid, __u64 gid,
- dev_t device, const struct nls_table *nls_codepage)
+ char *fileName, __u64 mode, __u64 uid, __u64 gid,
+ dev_t device, const struct nls_table *nls_codepage,
+ int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -3664,9 +3759,8 @@ setPermsRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, fileName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -3789,7 +3883,7 @@ ssize_t
CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char * EAData, size_t buf_size,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
/* BB assumes one setup word */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3810,9 +3904,8 @@ QAllEAsRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -3934,7 +4027,7 @@ QAllEAsRetry:
ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
const unsigned char * searchName,const unsigned char * ea_name,
unsigned char * ea_value, size_t buf_size,
- const struct nls_table *nls_codepage)
+ const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
@@ -3954,9 +4047,8 @@ QEARetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
@@ -4082,7 +4174,8 @@ QEARetry:
int
CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
const char * ea_name, const void * ea_value,
- const __u16 ea_value_len, const struct nls_table *nls_codepage)
+ const __u16 ea_value_len, const struct nls_table *nls_codepage,
+ int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -4101,9 +4194,8 @@ SetEARetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__u16 *) pSMB->FileName, fileName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 40470b9d5477..e568cc47a7f9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/connect.c
*
- * Copyright (C) International Business Machines Corp., 2002,2004
+ * Copyright (C) International Business Machines Corp., 2002,2005
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/utsname.h>
#include <linux/mempool.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include "cifspdu.h"
@@ -72,6 +73,7 @@ struct smb_vol {
unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
unsigned direct_io:1;
+ unsigned remap:1; /* set to remap seven reserved chars in filenames */
unsigned int rsize;
unsigned int wsize;
unsigned int sockopt;
@@ -114,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock);
server->maxBuf = 0;
- cFYI(1, ("Reconnecting tcp session "));
+ cFYI(1, ("Reconnecting tcp session"));
/* before reconnecting the tcp session, mark the smb session (uid)
and the tid bad so they are not used until reconnected */
@@ -155,9 +157,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
qhead);
if(mid_entry) {
if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
- /* Mark other intransit requests as needing retry so
- we do not immediately mark the session bad again
- (ie after we reconnect below) as they timeout too */
+ /* Mark other intransit requests as needing
+ retry so we do not immediately mark the
+ session bad again (ie after we reconnect
+ below) as they timeout too */
mid_entry->midState = MID_RETRY_NEEDED;
}
}
@@ -175,14 +178,14 @@ cifs_reconnect(struct TCP_Server_Info *server)
server->workstation_RFC1001_name);
}
if(rc) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(3 * HZ);
+ msleep(3000);
} else {
atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock);
if(server->tcpStatus != CifsExiting)
server->tcpStatus = CifsGood;
- spin_unlock(&GlobalMid_Lock);
+ server->sequence_number = 0;
+ spin_unlock(&GlobalMid_Lock);
/* atomic_set(&server->inFlight,0);*/
wake_up(&server->response_q);
}
@@ -190,12 +193,129 @@ cifs_reconnect(struct TCP_Server_Info *server)
return rc;
}
+/*
+ return codes:
+ 0 not a transact2, or all data present
+ >0 transact2 with that much data missing
+ -EINVAL = invalid transact2
+
+ */
+static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
+{
+ struct smb_t2_rsp * pSMBt;
+ int total_data_size;
+ int data_in_this_rsp;
+ int remaining;
+
+ if(pSMB->Command != SMB_COM_TRANSACTION2)
+ return 0;
+
+ /* check for plausible wct, bcc and t2 data and parm sizes */
+ /* check for parm and data offset going beyond end of smb */
+ if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+ cFYI(1,("invalid transact2 word count"));
+ return -EINVAL;
+ }
+
+ pSMBt = (struct smb_t2_rsp *)pSMB;
+
+ total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+ data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+ remaining = total_data_size - data_in_this_rsp;
+
+ if(remaining == 0)
+ return 0;
+ else if(remaining < 0) {
+ cFYI(1,("total data %d smaller than data in frame %d",
+ total_data_size, data_in_this_rsp));
+ return -EINVAL;
+ } else {
+ cFYI(1,("missing %d bytes from transact2, check next response",
+ remaining));
+ if(total_data_size > maxBufSize) {
+ cERROR(1,("TotalDataSize %d is over maximum buffer %d",
+ total_data_size,maxBufSize));
+ return -EINVAL;
+ }
+ return remaining;
+ }
+}
+
+static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
+{
+ struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
+ struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
+ int total_data_size;
+ int total_in_buf;
+ int remaining;
+ int total_in_buf2;
+ char * data_area_of_target;
+ char * data_area_of_buf2;
+ __u16 byte_count;
+
+ total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+
+ if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+ cFYI(1,("total data sizes of primary and secondary t2 differ"));
+ }
+
+ total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+ remaining = total_data_size - total_in_buf;
+
+ if(remaining < 0)
+ return -EINVAL;
+
+ if(remaining == 0) /* nothing to do, ignore */
+ return 0;
+
+ total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
+ if(remaining < total_in_buf2) {
+ cFYI(1,("transact2 2nd response contains too much data"));
+ }
+
+ /* find end of first SMB data area */
+ data_area_of_target = (char *)&pSMBt->hdr.Protocol +
+ le16_to_cpu(pSMBt->t2_rsp.DataOffset);
+ /* validate target area */
+
+ data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
+ le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+
+ data_area_of_target += total_in_buf;
+
+ /* copy second buffer into end of first buffer */
+ memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
+ total_in_buf += total_in_buf2;
+ pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
+ byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
+ byte_count += total_in_buf2;
+ BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
+
+ byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+ byte_count += total_in_buf2;
+
+ /* BB also add check that we are not beyond maximum buffer size */
+
+ pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
+
+ if(remaining == total_in_buf2) {
+ cFYI(1,("found the last secondary response"));
+ return 0; /* we are done */
+ } else /* more responses to go */
+ return 1;
+
+}
+
static int
cifs_demultiplex_thread(struct TCP_Server_Info *server)
{
int length;
unsigned int pdu_length, total_read;
struct smb_hdr *smb_buffer = NULL;
+ struct smb_hdr *bigbuf = NULL;
+ struct smb_hdr *smallbuf = NULL;
struct msghdr smb_msg;
struct kvec iov;
struct socket *csocket = server->ssocket;
@@ -204,6 +324,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
char *temp;
+ int isLargeBuf = FALSE;
+ int isMultiRsp;
+ int reconnect;
daemonize("cifsd");
allow_signal(SIGKILL);
@@ -221,17 +344,34 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
while (server->tcpStatus != CifsExiting) {
- if (smb_buffer == NULL)
- smb_buffer = cifs_buf_get();
- else
- memset(smb_buffer, 0, sizeof (struct smb_hdr));
-
- if (smb_buffer == NULL) {
- cERROR(1,("Can not get memory for SMB response"));
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ * 3); /* give system time to free memory */
- continue;
+ if (bigbuf == NULL) {
+ bigbuf = cifs_buf_get();
+ if(bigbuf == NULL) {
+ cERROR(1,("No memory for large SMB response"));
+ msleep(3000);
+ /* retry will check if exiting */
+ continue;
+ }
+ } else if(isLargeBuf) {
+ /* we are reusing a dirtry large buf, clear its start */
+ memset(bigbuf, 0, sizeof (struct smb_hdr));
}
+
+ if (smallbuf == NULL) {
+ smallbuf = cifs_small_buf_get();
+ if(smallbuf == NULL) {
+ cERROR(1,("No memory for SMB response"));
+ msleep(1000);
+ /* retry will check if exiting */
+ continue;
+ }
+ /* beginning of smb buffer is cleared in our buf_get */
+ } else /* if existing small buf clear beginning */
+ memset(smallbuf, 0, sizeof (struct smb_hdr));
+
+ isLargeBuf = FALSE;
+ isMultiRsp = FALSE;
+ smb_buffer = smallbuf;
iov.iov_base = smb_buffer;
iov.iov_len = 4;
smb_msg.msg_control = NULL;
@@ -243,176 +383,257 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
if(server->tcpStatus == CifsExiting) {
break;
} else if (server->tcpStatus == CifsNeedReconnect) {
- cFYI(1,("Reconnecting after server stopped responding"));
+ cFYI(1,("Reconnect after server stopped responding"));
cifs_reconnect(server);
cFYI(1,("call to reconnect done"));
csocket = server->ssocket;
continue;
} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1); /* minimum sleep to prevent looping
+ msleep(1); /* minimum sleep to prevent looping
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
continue;
} else if (length <= 0) {
if(server->tcpStatus == CifsNew) {
- cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
- /* some servers kill tcp session rather than returning
- smb negprot error in which case reconnecting here is
- not going to help - return error to mount */
+ cFYI(1,("tcp session abend after SMBnegprot"));
+ /* some servers kill the TCP session rather than
+ returning an SMB negprot error, in which
+ case reconnecting here is not going to help,
+ and so simply return error to mount */
break;
}
if(length == -EINTR) {
cFYI(1,("cifsd thread killed"));
break;
}
- cFYI(1,("Reconnecting after unexpected peek error %d",length));
+ cFYI(1,("Reconnect after unexpected peek error %d",
+ length));
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
- } else if (length > 3) {
- pdu_length = ntohl(smb_buffer->smb_buf_length);
- /* Only read pdu_length after below checks for too short (due
- to e.g. int overflow) and too long ie beyond end of buf */
- cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
-
- temp = (char *) smb_buffer;
- if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
- cFYI(0,("Received 4 byte keep alive packet"));
- } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
- cFYI(1,("Good RFC 1002 session rsp"));
- } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
- /* we get this from Windows 98 instead of error on SMB negprot response */
- cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
- if(server->tcpStatus == CifsNew) {
- /* if nack on negprot (rather than
- ret of smb negprot error) reconnecting
- not going to help, ret error to mount */
- break;
- } else {
- /* give server a second to
- clean up before reconnect attempt */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- /* always try 445 first on reconnect
- since we get NACK on some if we ever
- connected to port 139 (the NACK is
- since we do not begin with RFC1001
- session initialize frame) */
- server->addr.sockAddr.sin_port = htons(CIFS_PORT);
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- }
- } else if (temp[0] != (char) 0) {
- cERROR(1,("Unknown RFC 1002 frame"));
- cifs_dump_mem(" Received Data: ", temp, length);
- cifs_reconnect(server);
- csocket = server->ssocket;
- continue;
- } else {
- if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
- || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
- cERROR(1,
- ("Invalid size SMB length %d and pdu_length %d",
- length, pdu_length+4));
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- } else { /* length ok */
- length = 0;
- iov.iov_base = 4 + (char *)smb_buffer;
- iov.iov_len = pdu_length;
- for (total_read = 0;
- total_read < pdu_length;
- total_read += length) {
- length = kernel_recvmsg(csocket, &smb_msg,
- &iov, 1,
- pdu_length - total_read, 0);
- if (length == 0) {
- cERROR(1,
- ("Zero length receive when expecting %d ",
- pdu_length - total_read));
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- }
- }
- length += 4; /* account for rfc1002 hdr */
- }
+ } else if (length < 4) {
+ cFYI(1,
+ ("Frame under four bytes received (%d bytes long)",
+ length));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ }
- dump_smb(smb_buffer, length);
- if (checkSMB
- (smb_buffer, smb_buffer->Mid, total_read+4)) {
- cERROR(1, ("Bad SMB Received "));
- continue;
- }
+ /* the right amount was read from socket - 4 bytes */
- task_to_wake = NULL;
- spin_lock(&GlobalMid_Lock);
- list_for_each(tmp, &server->pending_mid_q) {
- mid_entry = list_entry(tmp, struct
- mid_q_entry,
- qhead);
+ pdu_length = ntohl(smb_buffer->smb_buf_length);
+ cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
- if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
- cFYI(1,
- (" Mid 0x%x matched - waking up ",mid_entry->mid));
- task_to_wake = mid_entry->tsk;
- mid_entry->resp_buf =
- smb_buffer;
- mid_entry->midState =
- MID_RESPONSE_RECEIVED;
- }
- }
- spin_unlock(&GlobalMid_Lock);
- if (task_to_wake) {
- smb_buffer = NULL; /* will be freed by users thread after he is done */
- wake_up_process(task_to_wake);
- } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
- cERROR(1, ("No task to wake, unknown frame rcvd!"));
- cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
- }
+ temp = (char *) smb_buffer;
+ if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
+ continue;
+ } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+ cFYI(1,("Good RFC 1002 session rsp"));
+ continue;
+ } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+ /* we get this from Windows 98 instead of
+ an error on SMB negprot response */
+ cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
+ temp[4]));
+ if(server->tcpStatus == CifsNew) {
+ /* if nack on negprot (rather than
+ ret of smb negprot error) reconnecting
+ not going to help, ret error to mount */
+ break;
+ } else {
+ /* give server a second to
+ clean up before reconnect attempt */
+ msleep(1000);
+ /* always try 445 first on reconnect
+ since we get NACK on some if we ever
+ connected to port 139 (the NACK is
+ since we do not begin with RFC1001
+ session initialize frame) */
+ server->addr.sockAddr.sin_port =
+ htons(CIFS_PORT);
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
}
- } else {
- cFYI(1,
- ("Frame less than four bytes received %d bytes long.",
- length));
+ } else if (temp[0] != (char) 0) {
+ cERROR(1,("Unknown RFC 1002 frame"));
+ cifs_dump_mem(" Received Data: ", temp, length);
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ continue;
+ }
+
+ /* else we have an SMB response */
+ if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+ (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
+ cERROR(1, ("Invalid size SMB length %d pdu_length %d",
+ length, pdu_length+4));
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
+ }
+
+ /* else length ok */
+ reconnect = 0;
+
+ if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
+ isLargeBuf = TRUE;
+ memcpy(bigbuf, smallbuf, 4);
+ smb_buffer = bigbuf;
}
- }
+ length = 0;
+ iov.iov_base = 4 + (char *)smb_buffer;
+ iov.iov_len = pdu_length;
+ for (total_read = 0; total_read < pdu_length;
+ total_read += length) {
+ length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
+ pdu_length - total_read, 0);
+ if((server->tcpStatus == CifsExiting) ||
+ (length == -EINTR)) {
+ /* then will exit */
+ reconnect = 2;
+ break;
+ } else if (server->tcpStatus == CifsNeedReconnect) {
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ /* Reconnect wakes up rspns q */
+ /* Now we will reread sock */
+ reconnect = 1;
+ break;
+ } else if ((length == -ERESTARTSYS) ||
+ (length == -EAGAIN)) {
+ msleep(1); /* minimum sleep to prevent looping,
+ allowing socket to clear and app
+ threads to set tcpStatus
+ CifsNeedReconnect if server hung*/
+ continue;
+ } else if (length <= 0) {
+ cERROR(1,("Received no data, expecting %d",
+ pdu_length - total_read));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ reconnect = 1;
+ break;
+ }
+ }
+ if(reconnect == 2)
+ break;
+ else if(reconnect == 1)
+ continue;
+
+ length += 4; /* account for rfc1002 hdr */
+
+
+ dump_smb(smb_buffer, length);
+ if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+ cERROR(1, ("Bad SMB Received "));
+ continue;
+ }
+
+
+ task_to_wake = NULL;
+ spin_lock(&GlobalMid_Lock);
+ list_for_each(tmp, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+
+ if ((mid_entry->mid == smb_buffer->Mid) &&
+ (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
+ (mid_entry->command == smb_buffer->Command)) {
+ if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
+ /* We have a multipart transact2 resp */
+ isMultiRsp = TRUE;
+ if(mid_entry->resp_buf) {
+ /* merge response - fix up 1st*/
+ if(coalesce_t2(smb_buffer,
+ mid_entry->resp_buf)) {
+ break;
+ } else {
+ /* all parts received */
+ goto multi_t2_fnd;
+ }
+ } else {
+ if(!isLargeBuf) {
+ cERROR(1,("1st trans2 resp needs bigbuf"));
+ /* BB maybe we can fix this up, switch
+ to already allocated large buffer? */
+ } else {
+ /* Have first buffer */
+ mid_entry->resp_buf =
+ smb_buffer;
+ mid_entry->largeBuf = 1;
+ bigbuf = NULL;
+ }
+ }
+ break;
+ }
+ mid_entry->resp_buf = smb_buffer;
+ if(isLargeBuf)
+ mid_entry->largeBuf = 1;
+ else
+ mid_entry->largeBuf = 0;
+multi_t2_fnd:
+ task_to_wake = mid_entry->tsk;
+ mid_entry->midState = MID_RESPONSE_RECEIVED;
+ break;
+ }
+ }
+ spin_unlock(&GlobalMid_Lock);
+ if (task_to_wake) {
+ /* Was previous buf put in mpx struct for multi-rsp? */
+ if(!isMultiRsp) {
+ /* smb buffer will be freed by user thread */
+ if(isLargeBuf) {
+ bigbuf = NULL;
+ } else
+ smallbuf = NULL;
+ }
+ wake_up_process(task_to_wake);
+ } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
+ && (isMultiRsp == FALSE)) {
+ cERROR(1, ("No task to wake, unknown frame rcvd!"));
+ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
+ }
+ } /* end while !EXITING */
+
spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting;
server->tsk = NULL;
- atomic_set(&server->inFlight, 0);
+ /* check if we have blocked requests that need to free */
+ /* Note that cifs_max_pending is normally 50, but
+ can be set at module install time to as little as two */
+ if(atomic_read(&server->inFlight) >= cifs_max_pending)
+ atomic_set(&server->inFlight, cifs_max_pending - 1);
+ /* We do not want to set the max_pending too low or we
+ could end up with the counter going negative */
spin_unlock(&GlobalMid_Lock);
/* Although there should not be any requests blocked on
this queue it can not hurt to be paranoid and try to wake up requests
- that may haven been blocked when more than 50 at time were on the wire
+ that may haven been blocked when more than 50 at time were on the wire
to the same server - they now will see the session is in exit state
and get out of SendReceive. */
wake_up_all(&server->request_q);
/* give those requests time to exit */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/8);
-
+ msleep(125);
+
if(server->ssocket) {
sock_release(csocket);
server->ssocket = NULL;
}
- if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
- cifs_buf_release(smb_buffer);
+ /* buffer usuallly freed in free_mid - need to free it here on exit */
+ if (bigbuf != NULL)
+ cifs_buf_release(bigbuf);
+ if (smallbuf != NULL)
+ cifs_small_buf_release(smallbuf);
read_lock(&GlobalSMBSeslock);
if (list_empty(&server->pending_mid_q)) {
- /* loop through server session structures attached to this and mark them dead */
+ /* loop through server session structures attached to this and
+ mark them dead */
list_for_each(tmp, &GlobalSMBSessionList) {
ses =
list_entry(tmp, struct cifsSesInfo,
@@ -424,12 +645,23 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
read_unlock(&GlobalSMBSeslock);
} else {
+ /* although we can not zero the server struct pointer yet,
+ since there are active requests which may depnd on them,
+ mark the corresponding SMB sessions as exiting too */
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ ses = list_entry(tmp, struct cifsSesInfo,
+ cifsSessionList);
+ if (ses->server == server) {
+ ses->status = CifsExiting;
+ }
+ }
+
spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
cFYI(1,
- (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
+ ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
task_to_wake = mid_entry->tsk;
if(task_to_wake) {
wake_up_process(task_to_wake);
@@ -438,47 +670,51 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
spin_unlock(&GlobalMid_Lock);
read_unlock(&GlobalSMBSeslock);
- set_current_state(TASK_INTERRUPTIBLE);
/* 1/8th of sec is more than enough time for them to exit */
- schedule_timeout(HZ/8);
+ msleep(125);
}
if (list_empty(&server->pending_mid_q)) {
/* mpx threads have not exited yet give them
at least the smb send timeout time for long ops */
+ /* due to delays on oplock break requests, we need
+ to wait at least 45 seconds before giving up
+ on a request getting a response and going ahead
+ and killing cifsd */
cFYI(1, ("Wait for exit from demultiplex thread"));
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(46 * HZ);
+ msleep(46000);
/* if threads still have not exited they are probably never
coming home not much else we can do but free the memory */
}
- kfree(server);
write_lock(&GlobalSMBSeslock);
atomic_dec(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
+
+ /* last chance to mark ses pointers invalid
+ if there are any pointing to this (e.g
+ if a crazy root user tried to kill cifsd
+ kernel thread explicitly this might happen) */
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ ses = list_entry(tmp, struct cifsSesInfo,
+ cifsSessionList);
+ if (ses->server == server) {
+ ses->server = NULL;
+ }
+ }
write_unlock(&GlobalSMBSeslock);
+
+ kfree(server);
if(length > 0) {
mempool_resize(cifs_req_poolp,
length + cifs_min_rcv,
GFP_KERNEL);
}
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/4);
+
+ msleep(250);
return 0;
}
-static void *
-cifs_kcalloc(size_t size, unsigned int __nocast type)
-{
- void *addr;
- addr = kmalloc(size, type);
- if (addr)
- memset(addr, 0, size);
- return addr;
-}
-
static int
cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
{
@@ -495,7 +731,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* does not have to be a perfect mapping since the field is
informational, only used for servers that do not support
port 445 and it can be overridden at mount time */
- vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
+ vol->source_rfc1001_name[i] =
+ toupper(system_utsname.nodename[i]);
}
vol->source_rfc1001_name[15] = 0;
@@ -570,14 +807,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* NB: password legally can have multiple commas and
the only illegal character in a password is null */
- if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
+ if ((value[temp_len] == 0) &&
+ (value[temp_len+1] == separator[0])) {
/* reinsert comma */
value[temp_len] = separator[0];
temp_len+=2; /* move after the second comma */
while(value[temp_len] != 0) {
if (value[temp_len] == separator[0]) {
- if (value[temp_len+1] == separator[0]) {
- temp_len++; /* skip second comma */
+ if (value[temp_len+1] ==
+ separator[0]) {
+ /* skip second comma */
+ temp_len++;
} else {
/* single comma indicating start
of next parm */
@@ -596,17 +836,26 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* go from value to value + temp_len condensing
double commas to singles. Note that this ends up
allocating a few bytes too many, which is ok */
- vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
+ vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+ if(vol->password == NULL) {
+ printk("CIFS: no memory for pass\n");
+ return 1;
+ }
for(i=0,j=0;i<temp_len;i++,j++) {
vol->password[j] = value[i];
- if(value[i] == separator[0] && value[i+1] == separator[0]) {
+ if(value[i] == separator[0]
+ && value[i+1] == separator[0]) {
/* skip second comma */
i++;
}
}
vol->password[j] = 0;
} else {
- vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
+ vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
+ if(vol->password == NULL) {
+ printk("CIFS: no memory for pass\n");
+ return 1;
+ }
strcpy(vol->password, value);
}
} else if (strnicmp(data, "ip", 2) == 0) {
@@ -770,6 +1019,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->noperm = 0;
} else if (strnicmp(data, "noperm", 6) == 0) {
vol->noperm = 1;
+ } else if (strnicmp(data, "mapchars", 8) == 0) {
+ vol->remap = 1;
+ } else if (strnicmp(data, "nomapchars", 10) == 0) {
+ vol->remap = 0;
} else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -918,14 +1171,15 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- const char *old_path, const struct nls_table *nls_codepage)
+ const char *old_path, const struct nls_table *nls_codepage,
+ int remap)
{
unsigned char *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
- &num_referrals, &referrals);
+ &num_referrals, &referrals, remap);
/* BB Add in code to: if valid refrl, if not ip address contact
the helper that resolves tcp names, mount to it, try to
@@ -940,7 +1194,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
- unsigned int *pnum_referrals, unsigned char ** preferrals)
+ unsigned int *pnum_referrals,
+ unsigned char ** preferrals, int remap)
{
char *temp_unc;
int rc = 0;
@@ -965,7 +1220,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
}
if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
- pnum_referrals, nls_codepage);
+ pnum_referrals, nls_codepage, remap);
return rc;
}
@@ -1062,7 +1317,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
sessinit is sent but no second negprot */
struct rfc1002_session_packet * ses_init_buf;
struct smb_hdr * smb_buf;
- ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+ ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
if(ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32;
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
@@ -1352,6 +1607,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} else
rc = 0;
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+ srvTcp->sequence_number = 0;
}
}
@@ -1419,6 +1675,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
if(volume_info.server_ino)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+ if(volume_info.remap)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
if(volume_info.no_xattr)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
if(volume_info.direct_io) {
@@ -1447,11 +1705,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') ==
NULL)) {
- rc = connect_to_dfs_path(xid,
- pSesInfo,
- "",
- cifs_sb->
- local_nls);
+ rc = connect_to_dfs_path(xid, pSesInfo,
+ "", cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if(volume_info.UNC)
kfree(volume_info.UNC);
FreeXid(xid);
@@ -1514,10 +1771,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
tcon->ses = pSesInfo;
/* do not care if following two calls succeed - informational only */
- CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
- CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
+ CIFSSMBQFSDeviceInfo(xid, tcon);
+ CIFSSMBQFSAttributeInfo(xid, tcon);
if (tcon->ses->capabilities & CAP_UNIX) {
- if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
+ if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
if(!volume_info.no_psx_acl) {
if(CIFS_UNIX_POSIX_ACL_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))
@@ -1707,7 +1964,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
- ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+ if(ses->serverOS == NULL)
+ goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)bcc_ptr, len,nls_codepage);
bcc_ptr += 2 * (len + 1);
@@ -1717,7 +1976,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1);
- ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
+ ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+ if(ses->serverNOS == NULL)
+ goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverNOS,
(wchar_t *)bcc_ptr,len,nls_codepage);
bcc_ptr += 2 * (len + 1);
@@ -1730,10 +1991,12 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
}
remaining_words -= len + 1;
if (remaining_words > 0) {
- len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
ses->serverDomain =
- cifs_kcalloc(2*(len+1),GFP_KERNEL);
+ kcalloc(1, 2*(len+1),GFP_KERNEL);
+ if(ses->serverDomain == NULL)
+ goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverDomain,
(wchar_t *)bcc_ptr,len,nls_codepage);
bcc_ptr += 2 * (len + 1);
@@ -1741,21 +2004,25 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
ses->serverDomain[1+(2*len)] = 0;
} /* else no more room so create dummy domain string */
else
- ses->serverDomain =
- cifs_kcalloc(2,
- GFP_KERNEL);
+ ses->serverDomain =
+ kcalloc(1, 2, GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
+ /* if these kcallocs fail not much we
+ can do, but better to not fail the
+ sesssetup itself */
ses->serverDomain =
- cifs_kcalloc(2, GFP_KERNEL);
+ kcalloc(1, 2, GFP_KERNEL);
ses->serverNOS =
- cifs_kcalloc(2, GFP_KERNEL);
+ kcalloc(1, 2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+ if(ses->serverOS == NULL)
+ goto sesssetup_nomem;
strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len;
@@ -1763,14 +2030,18 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+ if(ses->serverNOS == NULL)
+ goto sesssetup_nomem;
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+ if(ses->serverDomain == NULL)
+ goto sesssetup_nomem;
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
@@ -1790,7 +2061,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
smb_buffer_response->WordCount));
rc = -EIO;
}
-
+sesssetup_nomem: /* do not return an error on nomem for the info strings,
+ since that could make reconnection harder, and
+ reconnection might be needed to free memory */
if (smb_buffer)
cifs_buf_release(smb_buffer);
@@ -1967,7 +2240,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kcalloc(1, 2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
@@ -1981,7 +2254,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
remaining_words
- 1);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kcalloc(1, 2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->serverNOS,
(wchar_t *)bcc_ptr,
@@ -1994,7 +2267,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
- ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
cifs_strfromUCS_le(ses->serverDomain,
(wchar_t *)bcc_ptr,
len,
@@ -2005,10 +2278,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- cifs_kcalloc(2,GFP_KERNEL);
+ kcalloc(1, 2,GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
+ ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
}
} else { /* ASCII */
@@ -2016,7 +2289,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
+ ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len;
@@ -2024,14 +2297,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
@@ -2281,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kcalloc(1, 2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
@@ -2296,7 +2569,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
remaining_words
- 1);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kcalloc(1, 2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
@@ -2313,7 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
ses->serverDomain =
- cifs_kcalloc(2 *
+ kcalloc(1, 2 *
(len +
1),
GFP_KERNEL);
@@ -2339,13 +2612,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
} /* else no more room so create dummy domain string */
else
ses->serverDomain =
- cifs_kcalloc(2,
+ kcalloc(1, 2,
GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
ses->serverDomain =
- cifs_kcalloc(2, GFP_KERNEL);
+ kcalloc(1, 2, GFP_KERNEL);
ses->serverNOS =
- cifs_kcalloc(2, GFP_KERNEL);
+ kcalloc(1, 2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
@@ -2353,7 +2626,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
ses->serverOS =
- cifs_kcalloc(len + 1,
+ kcalloc(1, len + 1,
GFP_KERNEL);
strncpy(ses->serverOS,
bcc_ptr, len);
@@ -2364,7 +2637,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
len = strnlen(bcc_ptr, 1024);
ses->serverNOS =
- cifs_kcalloc(len + 1,
+ kcalloc(1, len + 1,
GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
@@ -2373,7 +2646,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
len = strnlen(bcc_ptr, 1024);
ses->serverDomain =
- cifs_kcalloc(len + 1,
+ kcalloc(1, len + 1,
GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
@@ -2675,7 +2948,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kcalloc(1, 2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
(wchar_t *)
bcc_ptr, len,
@@ -2690,7 +2963,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
remaining_words
- 1);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kcalloc(1, 2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
@@ -2706,7 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string not always null terminated (e.g. for Windows XP & 2000) */
ses->serverDomain =
- cifs_kcalloc(2 *
+ kcalloc(1, 2 *
(len +
1),
GFP_KERNEL);
@@ -2731,17 +3004,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
= 0;
} /* else no more room so create dummy domain string */
else
- ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
+ ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
if (((long) bcc_ptr + len) -
(long) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len;
@@ -2749,14 +3022,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
+ ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
+ ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
@@ -2868,7 +3141,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
if(tcon->nativeFileSystem)
kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- cifs_kcalloc(length + 2, GFP_KERNEL);
+ kcalloc(1, length + 2, GFP_KERNEL);
cifs_strfromUCS_le(tcon->nativeFileSystem,
(wchar_t *) bcc_ptr,
length, nls_codepage);
@@ -2886,7 +3159,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
if(tcon->nativeFileSystem)
kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- cifs_kcalloc(length + 1, GFP_KERNEL);
+ kcalloc(1, length + 1, GFP_KERNEL);
strncpy(tcon->nativeFileSystem, bcc_ptr,
length);
}
@@ -2959,6 +3232,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
int rc = 0;
char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
int ntlmv2_flag = FALSE;
+ int first_time = 0;
/* what if server changes its buffer size after dropping the session? */
if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
@@ -2977,12 +3251,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
spin_unlock(&GlobalMid_Lock);
}
+ first_time = 1;
}
if (!rc) {
pSesInfo->capabilities = pSesInfo->server->capabilities;
if(linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX);
- pSesInfo->sequence_number = 0;
+ /* pSesInfo->sequence_number = 0;*/
cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
pSesInfo->server->secMode,
pSesInfo->server->capabilities,
@@ -3015,7 +3290,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
if(v2_response) {
CalcNTLMv2_response(pSesInfo,v2_response);
-/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
+ /* if(first_time)
+ cifs_calculate_ntlmv2_mac_key(
+ pSesInfo->server->mac_signing_key,
+ response, ntlm_session_key, */
kfree(v2_response);
/* BB Put dummy sig in SessSetup PDU? */
} else {
@@ -3028,9 +3306,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey,
ntlm_session_key);
- cifs_calculate_mac_key(pSesInfo->mac_signing_key,
- ntlm_session_key,
- pSesInfo->password);
+ if(first_time)
+ cifs_calculate_mac_key(
+ pSesInfo->server->mac_signing_key,
+ ntlm_session_key,
+ pSesInfo->password);
}
/* for better security the weaker lanman hash not sent
in AuthSessSetup so we no longer calculate it */
@@ -3046,8 +3326,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey,
ntlm_session_key);
- cifs_calculate_mac_key(pSesInfo->mac_signing_key,
- ntlm_session_key, pSesInfo->password);
+ if(first_time)
+ cifs_calculate_mac_key(
+ pSesInfo->server->mac_signing_key,
+ ntlm_session_key, pSesInfo->password);
+
rc = CIFSSessSetup(xid, pSesInfo,
ntlm_session_key, nls_info);
}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index f54e1866f0f4..e3137aa48cdd 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -101,68 +101,15 @@ cifs_bp_rename_retry:
return full_path;
}
-/* Note: caller must free return buffer */
-char *
-build_wildcard_path_from_dentry(struct dentry *direntry)
+/* char * build_wildcard_path_from_dentry(struct dentry *direntry)
{
- struct dentry *temp;
- int namelen = 0;
- char *full_path;
-
- if(direntry == NULL)
- return NULL; /* not much we can do if dentry is freed and
- we need to reopen the file after it was closed implicitly
- when the server crashed */
-
-cifs_bwp_rename_retry:
- for (temp = direntry; !IS_ROOT(temp);) {
- namelen += (1 + temp->d_name.len);
- temp = temp->d_parent;
- if(temp == NULL) {
- cERROR(1,("corrupt dentry"));
- return NULL;
- }
- }
-
- full_path = kmalloc(namelen+3, GFP_KERNEL);
if(full_path == NULL)
return full_path;
full_path[namelen] = '\\';
full_path[namelen+1] = '*';
- full_path[namelen+2] = 0; /* trailing null */
-
- for (temp = direntry; !IS_ROOT(temp);) {
- namelen -= 1 + temp->d_name.len;
- if (namelen < 0) {
- break;
- } else {
- full_path[namelen] = '\\';
- strncpy(full_path + namelen + 1, temp->d_name.name,
- temp->d_name.len);
- cFYI(0, (" name: %s ", full_path + namelen));
- }
- temp = temp->d_parent;
- if(temp == NULL) {
- cERROR(1,("corrupt dentry"));
- kfree(full_path);
- return NULL;
- }
- }
- if (namelen != 0) {
- cERROR(1,
- ("We did not end path lookup where we expected namelen is %d",
- namelen));
- /* presumably this is only possible if we were racing with a rename
- of one of the parent directories (we can not lock the dentries
- above us to prevent this, but retrying should be harmless) */
- kfree(full_path);
- namelen = 0;
- goto cifs_bwp_rename_retry;
- }
-
- return full_path;
-}
+ full_path[namelen+2] = 0;
+BB remove above eight lines BB */
/* Inode operations in similar order to how they appear in the Linux file fs.h */
@@ -235,7 +182,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR,
- &fileHandle, &oplock, buf, cifs_sb->local_nls);
+ &fileHandle, &oplock, buf, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cFYI(1, ("cifs_create returned 0x%x ", rc));
} else {
@@ -248,13 +196,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
(__u64)current->euid,
(__u64)current->egid,
0 /* dev */,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
(__u64)-1,
(__u64)-1,
0 /* dev */,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
}
else {
/* BB implement via Windows security descriptors */
@@ -284,51 +236,48 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
/* mknod case - do not leave file open */
CIFSSMBClose(xid, pTcon, fileHandle);
} else if(newinode) {
- pCifsFile = (struct cifsFileInfo *)
+ pCifsFile =
kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
-
- if (pCifsFile) {
- memset((char *)pCifsFile, 0,
- sizeof (struct cifsFileInfo));
- pCifsFile->netfid = fileHandle;
- pCifsFile->pid = current->tgid;
- pCifsFile->pInode = newinode;
- pCifsFile->invalidHandle = FALSE;
- pCifsFile->closePend = FALSE;
- init_MUTEX(&pCifsFile->fh_sem);
- /* put the following in at open now */
- /* pCifsFile->pfile = file; */
- write_lock(&GlobalSMBSeslock);
- list_add(&pCifsFile->tlist,&pTcon->openFileList);
- pCifsInode = CIFS_I(newinode);
- if(pCifsInode) {
+
+ if(pCifsFile == NULL)
+ goto cifs_create_out;
+ memset((char *)pCifsFile, 0,
+ sizeof (struct cifsFileInfo));
+ pCifsFile->netfid = fileHandle;
+ pCifsFile->pid = current->tgid;
+ pCifsFile->pInode = newinode;
+ pCifsFile->invalidHandle = FALSE;
+ pCifsFile->closePend = FALSE;
+ init_MUTEX(&pCifsFile->fh_sem);
+ /* set the following in open now
+ pCifsFile->pfile = file; */
+ write_lock(&GlobalSMBSeslock);
+ list_add(&pCifsFile->tlist,&pTcon->openFileList);
+ pCifsInode = CIFS_I(newinode);
+ if(pCifsInode) {
/* if readable file instance put first in list*/
- if (write_only == TRUE) {
- list_add_tail(&pCifsFile->flist,
- &pCifsInode->openFileList);
- } else {
- list_add(&pCifsFile->flist,
- &pCifsInode->openFileList);
- }
- if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
- pCifsInode->clientCanCacheAll = TRUE;
- pCifsInode->clientCanCacheRead = TRUE;
- cFYI(1,("Exclusive Oplock granted on inode %p",
- newinode));
- } else if((oplock & 0xF) == OPLOCK_READ)
- pCifsInode->clientCanCacheRead = TRUE;
+ if (write_only == TRUE) {
+ list_add_tail(&pCifsFile->flist,
+ &pCifsInode->openFileList);
+ } else {
+ list_add(&pCifsFile->flist,
+ &pCifsInode->openFileList);
}
- write_unlock(&GlobalSMBSeslock);
+ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+ pCifsInode->clientCanCacheAll = TRUE;
+ pCifsInode->clientCanCacheRead = TRUE;
+ cFYI(1,("Exclusive Oplock for inode %p",
+ newinode));
+ } else if((oplock & 0xF) == OPLOCK_READ)
+ pCifsInode->clientCanCacheRead = TRUE;
}
+ write_unlock(&GlobalSMBSeslock);
}
}
-
- if (buf)
- kfree(buf);
- if (full_path)
- kfree(full_path);
+cifs_create_out:
+ kfree(buf);
+ kfree(full_path);
FreeXid(xid);
-
return rc;
}
@@ -359,11 +308,15 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode,(__u64)current->euid,(__u64)current->egid,
- device_number, cifs_sb->local_nls);
+ device_number, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
rc = CIFSSMBUnixSetPerms(xid, pTcon,
full_path, mode, (__u64)-1, (__u64)-1,
- device_number, cifs_sb->local_nls);
+ device_number, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if(!rc) {
@@ -375,10 +328,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
}
}
- if (full_path)
- kfree(full_path);
+ kfree(full_path);
FreeXid(xid);
-
return rc;
}
@@ -447,43 +398,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
if file exists or not but no access BB */
}
- if (full_path)
- kfree(full_path);
+ kfree(full_path);
FreeXid(xid);
return ERR_PTR(rc);
}
-int
-cifs_dir_open(struct inode *inode, struct file *file)
-{ /* NB: currently unused since searches are opened in readdir */
- int rc = 0;
- int xid;
- struct cifs_sb_info *cifs_sb;
- struct cifsTconInfo *pTcon;
- char *full_path = NULL;
-
- xid = GetXid();
-
- cifs_sb = CIFS_SB(inode->i_sb);
- pTcon = cifs_sb->tcon;
-
- if(file->f_dentry) {
- down(&file->f_dentry->d_sb->s_vfs_rename_sem);
- full_path = build_wildcard_path_from_dentry(file->f_dentry);
- up(&file->f_dentry->d_sb->s_vfs_rename_sem);
- } else {
- FreeXid(xid);
- return -EIO;
- }
-
- cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path));
-
- if (full_path)
- kfree(full_path);
- FreeXid(xid);
- return rc;
-}
-
static int
cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
{
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index 9d24c40f1967..7d2a9202c39a 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -92,7 +92,8 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
- &netfid, &oplock,NULL, cifs_sb->local_nls);
+ &netfid, &oplock,NULL, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB fixme - add this handle to a notify handle list */
if(rc) {
cERROR(1,("Could not open directory for notify")); /* BB remove BB */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dcab7cf1b53b..dde2d251fc3d 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -254,7 +254,8 @@ int cifs_open(struct inode *inode, struct file *file)
}
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, buf,
- cifs_sb->local_nls);
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+ & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cFYI(1, ("cifs_open returned 0x%x ", rc));
goto out;
@@ -287,7 +288,9 @@ int cifs_open(struct inode *inode, struct file *file)
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
inode->i_mode,
(__u64)-1, (__u64)-1, 0 /* dev */,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
/* BB implement via Windows security descriptors eg
CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
@@ -387,7 +390,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
} */
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb->local_nls);
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
up(&pCifsFile->fh_sem);
cFYI(1, ("cifs_open returned 0x%x ", rc));
@@ -465,8 +469,10 @@ int cifs_close(struct inode *inode, struct file *file)
write_lock(&file->f_owner.lock);
}
}
+ write_lock(&GlobalSMBSeslock);
list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
+ write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
kfree(pSMBFile->search_resume_name);
kfree(file->private_data);
@@ -506,7 +512,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
pTcon = cifs_sb->tcon;
cFYI(1, ("Freeing private data in close dir"));
- if (pCFileStruct->srch_inf.endOfSearch == FALSE) {
+ if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&
+ (pCFileStruct->invalidHandle == FALSE)) {
pCFileStruct->invalidHandle = TRUE;
rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
cFYI(1, ("Closing uncompleted readdir with rc %d",
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d73b0aa86775..670947288262 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -44,7 +44,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
cFYI(1, (" Getting info on %s ", search_path));
/* could have done a find first instead but this returns more info */
rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
- cifs_sb->local_nls);
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
/* dump_mem("\nUnixQPathInfo return data", &findData,
sizeof(findData)); */
if (rc) {
@@ -63,7 +64,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
strncat(tmp_path, search_path, MAX_PATHCONF);
rc = connect_to_dfs_path(xid, pTcon->ses,
/* treename + */ tmp_path,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(tmp_path);
/* BB fix up inode etc. */
@@ -210,7 +213,8 @@ int cifs_get_inode_info(struct inode **pinode,
pfindData = (FILE_ALL_INFO *)buf;
/* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
- cifs_sb->local_nls);
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
}
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) {
@@ -230,7 +234,9 @@ int cifs_get_inode_info(struct inode **pinode,
strncat(tmp_path, search_path, MAX_PATHCONF);
rc = connect_to_dfs_path(xid, pTcon->ses,
/* treename + */ tmp_path,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(tmp_path);
/* BB fix up inode etc. */
} else if (rc) {
@@ -268,7 +274,9 @@ int cifs_get_inode_info(struct inode **pinode,
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
search_path, &inode_num,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if(rc1) {
cFYI(1,("GetSrvInodeNum rc %d", rc1));
/* BB EOPNOSUPP disable SERVER_INUM? */
@@ -410,7 +418,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FreeXid(xid);
return -ENOMEM;
}
- rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
+ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
direntry->d_inode->i_nlink--;
@@ -422,10 +431,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
- &netfid, &oplock, NULL, cifs_sb->local_nls);
+ &netfid, &oplock, NULL, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) {
CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
direntry->d_inode->i_nlink--;
}
@@ -439,7 +452,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
if (!(pTcon->ses->flags & CIFS_SES_NT4))
rc = CIFSSMBSetTimes(xid, pTcon, full_path,
pinfo_buf,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EOPNOTSUPP;
@@ -461,7 +476,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FILE_OPEN, SYNCHRONIZE |
FILE_WRITE_ATTRIBUTES, 0,
&netfid, &oplock, NULL,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) {
rc = CIFSSMBSetFileTimes(xid, pTcon,
pinfo_buf,
@@ -472,8 +489,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
kfree(pinfo_buf);
}
if (rc==0) {
- rc = CIFSSMBDelFile(xid, pTcon, full_path,
- cifs_sb->local_nls);
+ rc = CIFSSMBDelFile(xid, pTcon, full_path,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
direntry->d_inode->i_nlink--;
} else if (rc == -ETXTBSY) {
@@ -485,11 +504,15 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CREATE_NOT_DIR |
CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) {
CIFSSMBRenameOpenFile(xid, pTcon,
netfid, NULL,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
direntry->d_inode->i_nlink--;
}
@@ -534,7 +557,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
return -ENOMEM;
}
/* BB add setting the equivalent of mode via CreateX w/ACLs */
- rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
+ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
d_drop(direntry);
@@ -558,12 +582,16 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
(__u64)current->euid,
(__u64)current->egid,
0 /* dev_t */,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode, (__u64)-1,
(__u64)-1, 0 /* dev_t */,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
}
else {
/* BB to be implemented via Windows secrty descriptors
@@ -600,7 +628,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
return -ENOMEM;
}
- rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
+ rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
inode->i_nlink--;
@@ -653,7 +682,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
}
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
- cifs_sb_source->local_nls);
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == -EEXIST) {
/* check if they are the same file because rename of hardlinked
files is a noop */
@@ -665,11 +696,16 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
if (info_buf_source != NULL) {
info_buf_target = info_buf_source + 1;
rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
- info_buf_source, cifs_sb_source->local_nls);
+ info_buf_source, cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == 0) {
rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
info_buf_target,
- cifs_sb_target->local_nls);
+ cifs_sb_target->local_nls,
+ /* remap based on source sb */
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if ((rc == 0) &&
(info_buf_source->UniqueId ==
@@ -685,7 +721,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
cifs_unlink(target_inode, target_direntry);
rc = CIFSSMBRename(xid, pTcon, fromName,
toName,
- cifs_sb_source->local_nls);
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags
+ & CIFS_MOUNT_MAP_SPECIAL_CHR);
}
kfree(info_buf_source);
} /* if we can not get memory just leave rc as EEXIST */
@@ -705,10 +743,14 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
might not right be right access to request */
rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb_source->local_nls);
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) {
CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
- cifs_sb_source->local_nls);
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
}
}
@@ -962,7 +1004,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
it by handle */
rc = CIFSSMBSetEOF(xid, pTcon, full_path,
attrs->ia_size, FALSE,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
}
@@ -999,7 +1043,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
&& (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
- 0 /* dev_t */, cifs_sb->local_nls);
+ 0 /* dev_t */, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
else if (attrs->ia_valid & ATTR_MODE) {
if ((mode & S_IWUGO) == 0) /* not writeable */ {
if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
@@ -1048,7 +1094,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
via Handle (SetFileInfo) instead of by path */
if (!(pTcon->ses->flags & CIFS_SES_NT4))
rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EOPNOTSUPP;
@@ -1063,7 +1111,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
CREATE_NOT_DIR, &netfid, &oplock,
- NULL, cifs_sb->local_nls);
+ NULL, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) {
rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
netfid);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index b4b8e201d428..b0ea6687ab55 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -20,30 +20,93 @@
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
+#include "cifsfs.h"
+
+#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg)
{
int rc = -ENOTTY; /* strange error - but the precedent */
+ int xid;
+ struct cifs_sb_info *cifs_sb;
+#ifdef CONFIG_CIFS_POSIX
+ __u64 ExtAttrBits = 0;
+ __u64 ExtAttrMask = 0;
+ __u64 caps;
+ struct cifsTconInfo *tcon;
+ struct cifsFileInfo *pSMBFile =
+ (struct cifsFileInfo *)filep->private_data;
+#endif /* CONFIG_CIFS_POSIX */
+
+ xid = GetXid();
+
+ cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg));
+
+ cifs_sb = CIFS_SB(inode->i_sb);
+
#ifdef CONFIG_CIFS_POSIX
- cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg));
+ tcon = cifs_sb->tcon;
+ if(tcon)
+ caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
+ else {
+ rc = -EIO;
+ FreeXid(xid);
+ return -EIO;
+ }
+#endif /* CONFIG_CIFS_POSIX */
+
switch(command) {
+ case CIFS_IOC_CHECKUMOUNT:
+ cFYI(1,("User unmount attempted"));
+ if(cifs_sb->mnt_uid == current->uid)
+ rc = 0;
+ else {
+ rc = -EACCES;
+ cFYI(1,("uids do not match"));
+ }
+ break;
+#ifdef CONFIG_CIFS_POSIX
case EXT2_IOC_GETFLAGS:
- cFYI(1,("get flags not implemented yet"));
- return -EOPNOTSUPP;
+ if(CIFS_UNIX_EXTATTR_CAP & caps) {
+ if (pSMBFile == NULL)
+ break;
+ rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+ &ExtAttrBits, &ExtAttrMask);
+ if(rc == 0)
+ rc = put_user(ExtAttrBits &
+ EXT2_FL_USER_VISIBLE,
+ (int __user *)arg);
+ }
+ break;
+
case EXT2_IOC_SETFLAGS:
+ if(CIFS_UNIX_EXTATTR_CAP & caps) {
+ if(get_user(ExtAttrBits,(int __user *)arg)) {
+ rc = -EFAULT;
+ break;
+ }
+ if (pSMBFile == NULL)
+ break;
+ /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
+ extAttrBits, &ExtAttrMask);*/
+
+ }
cFYI(1,("set flags not implemented yet"));
- return -EOPNOTSUPP;
+ break;
+#endif /* CONFIG_CIFS_POSIX */
default:
cFYI(1,("unsupported ioctl"));
- return rc;
+ break;
}
-#endif /* CONFIG_CIFS_POSIX */
+
+ FreeXid(xid);
return rc;
}
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 1455810ba1cb..bde0fabfece0 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -59,10 +59,14 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb_target->local_nls);
+ cifs_sb_target->local_nls,
+ cifs_sb_target->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
else {
rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb_target->local_nls);
+ cifs_sb_target->local_nls,
+ cifs_sb_target->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if(rc == -EIO)
rc = -EOPNOTSUPP;
}
@@ -260,7 +264,10 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cifs_sb->local_nls);
else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
- OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls);
+ OPEN_REPARSE_POINT,&fid, &oplock, NULL,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if(!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer,
@@ -279,7 +286,10 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
strncat(tmp_path, full_path, MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses, tmp_path,
- cifs_sb->local_nls, &num_referrals, &referrals);
+ cifs_sb->local_nls,
+ &num_referrals, &referrals,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
if((num_referrals == 0) && (rc == 0))
rc = -EACCES;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 7b38d3059a83..db14b503d89e 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -28,6 +28,7 @@
#include "cifs_debug.h"
#include "smberr.h"
#include "nterr.h"
+#include "cifs_unicode.h"
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
@@ -451,25 +452,30 @@ is_valid_oplock_break(struct smb_hdr *buf)
atomic_inc(&tcon->num_oplock_brks);
#endif
list_for_each(tmp1,&tcon->openFileList){
- netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
+ netfile = list_entry(tmp1,struct cifsFileInfo,
+ tlist);
if(pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode;
read_unlock(&GlobalSMBSeslock);
- cFYI(1,("Matching file id, processing oplock break"));
+ cFYI(1,("file id match, oplock break"));
pCifsInode =
CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = FALSE;
if(pSMB->OplockLevel == 0)
- pCifsInode->clientCanCacheRead = FALSE;
+ pCifsInode->clientCanCacheRead
+ = FALSE;
pCifsInode->oplockPending = TRUE;
- AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon);
+ AllocOplockQEntry(netfile->pInode,
+ netfile->netfid,
+ tcon);
cFYI(1,("about to wake up oplock thd"));
- wake_up_process(oplockThread);
+ if(oplockThread)
+ wake_up_process(oplockThread);
return TRUE;
}
}
read_unlock(&GlobalSMBSeslock);
- cFYI(1,("No matching file for oplock break on connection"));
+ cFYI(1,("No matching file for oplock break"));
return TRUE;
}
}
@@ -490,7 +496,7 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
buffer = (unsigned char *) smb_buf;
for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
- if (i % 8 == 0) { /* we have reached the beginning of line */
+ if (i % 8 == 0) { /* have reached the beginning of line */
printk(KERN_DEBUG "| ");
j = 0;
}
@@ -501,7 +507,7 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
else
debug_line[1 + (2 * j)] = '_';
- if (i % 8 == 7) { /* we have reached end of line, time to print ascii */
+ if (i % 8 == 7) { /* reached end of line, time to print ascii */
debug_line[16] = 0;
printk(" | %s\n", debug_line);
}
@@ -514,3 +520,141 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
printk( " | %s\n", debug_line);
return;
}
+
+/* Windows maps these to the user defined 16 bit Unicode range since they are
+ reserved symbols (along with \ and /), otherwise illegal to store
+ in filenames in NTFS */
+#define UNI_ASTERIK (__u16) ('*' + 0xF000)
+#define UNI_QUESTION (__u16) ('?' + 0xF000)
+#define UNI_COLON (__u16) (':' + 0xF000)
+#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
+#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
+#define UNI_PIPE (__u16) ('|' + 0xF000)
+#define UNI_SLASH (__u16) ('\\' + 0xF000)
+
+/* Convert 16 bit Unicode pathname from wire format to string in current code
+ page. Conversion may involve remapping up the seven characters that are
+ only legal in POSIX-like OS (if they are present in the string). Path
+ names are little endian 16 bit Unicode on the wire */
+int
+cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
+ const struct nls_table * cp)
+{
+ int i,j,len;
+ __u16 src_char;
+
+ for(i = 0, j = 0; i < maxlen; i++) {
+ src_char = le16_to_cpu(source[i]);
+ switch (src_char) {
+ case 0:
+ goto cUCS_out; /* BB check this BB */
+ case UNI_COLON:
+ target[j] = ':';
+ break;
+ case UNI_ASTERIK:
+ target[j] = '*';
+ break;
+ case UNI_QUESTION:
+ target[j] = '?';
+ break;
+ /* BB We can not handle remapping slash until
+ all the calls to build_path_from_dentry
+ are modified, as they use slash as separator BB */
+ /* case UNI_SLASH:
+ target[j] = '\\';
+ break;*/
+ case UNI_PIPE:
+ target[j] = '|';
+ break;
+ case UNI_GRTRTHAN:
+ target[j] = '>';
+ break;
+ case UNI_LESSTHAN:
+ target[j] = '<';
+ default:
+ len = cp->uni2char(src_char, &target[j],
+ NLS_MAX_CHARSET_SIZE);
+ if(len > 0) {
+ j += len;
+ continue;
+ } else {
+ target[j] = '?';
+ }
+ }
+ j++;
+ /* make sure we do not overrun callers allocated temp buffer */
+ if(j >= (2 * NAME_MAX))
+ break;
+ }
+cUCS_out:
+ target[j] = 0;
+ return j;
+}
+
+/* Convert 16 bit Unicode pathname to wire format from string in current code
+ page. Conversion may involve remapping up the seven characters that are
+ only legal in POSIX-like OS (if they are present in the string). Path
+ names are little endian 16 bit Unicode on the wire */
+int
+cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
+ const struct nls_table * cp, int mapChars)
+{
+ int i,j,charlen;
+ int len_remaining = maxlen;
+ char src_char;
+
+ if(!mapChars)
+ return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);
+
+ for(i = 0, j = 0; i < maxlen; j++) {
+ src_char = source[i];
+ switch (src_char) {
+ case 0:
+ goto ctoUCS_out;
+ case ':':
+ target[j] = cpu_to_le16(UNI_COLON);
+ break;
+ case '*':
+ target[j] = cpu_to_le16(UNI_ASTERIK);
+ break;
+ case '?':
+ target[j] = cpu_to_le16(UNI_QUESTION);
+ break;
+ case '<':
+ target[j] = cpu_to_le16(UNI_LESSTHAN);
+ break;
+ case '>':
+ target[j] = cpu_to_le16(UNI_GRTRTHAN);
+ break;
+ case '|':
+ target[j] = cpu_to_le16(UNI_PIPE);
+ break;
+ /* BB We can not handle remapping slash until
+ all the calls to build_path_from_dentry
+ are modified, as they use slash as separator BB */
+ /* case '\\':
+ target[j] = cpu_to_le16(UNI_SLASH);
+ break;*/
+ default:
+ charlen = cp->char2uni(source+i,
+ len_remaining, target+j);
+ /* if no match, use question mark, which
+ at least in some cases servers as wild card */
+ if(charlen < 1) {
+ target[j] = cpu_to_le16(0x003f);
+ charlen = 1;
+ }
+ len_remaining -= charlen;
+ /* character may take more than one byte in the
+ the source string, but will take exactly two
+ bytes in the target string */
+ i+= charlen;
+ continue;
+ }
+ i++; /* move to next char in source string */
+ len_remaining--;
+ }
+
+ctoUCS_out:
+ return i;
+}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 4e34c89cec5d..a92af41d4411 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -78,6 +78,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ErrQuota, -EDQUOT},
{ErrNotALink, -ENOLINK},
{ERRnetlogonNotStarted,-ENOPROTOOPT},
+ {ErrTooManyLinks,-EMLINK},
{0, 0}
};
@@ -206,7 +207,7 @@ static const struct {
{
ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
- ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, {
+ ERRDOS, ERRinvlevel, NT_STATUS_INVALID_INFO_CLASS}, {
ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
@@ -742,7 +743,7 @@ static const struct {
ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
- ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, {
+ ERRDOS, ErrTooManyLinks, NT_STATUS_TOO_MANY_LINKS}, {
ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
ERRDOS, 21, 0xc000026e}, {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index f8bea395ec9e..22557716f9af 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -3,7 +3,7 @@
*
* Directory search handling
*
- * Copyright (C) International Business Machines Corp., 2004
+ * Copyright (C) International Business Machines Corp., 2004, 2005
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -65,14 +65,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
struct cifsTconInfo *pTcon;
int rc = 0;
- cFYI(1, ("For %s ", qstring->name));
+ cFYI(1, ("For %s", qstring->name));
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon;
qstring->hash = full_name_hash(qstring->name, qstring->len);
tmp_dentry = d_lookup(file->f_dentry, qstring);
if (tmp_dentry) {
- cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
+ cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if(*ptmp_inode == NULL) {
@@ -105,8 +105,11 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
}
static void fill_in_inode(struct inode *tmp_inode,
- FILE_DIRECTORY_INFO *pfindData, int *pobject_type)
+ FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
{
+ loff_t local_size;
+ struct timespec local_mtime;
+
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
@@ -116,6 +119,10 @@ static void fill_in_inode(struct inode *tmp_inode,
cifsInfo->cifsAttrs = attr;
cifsInfo->time = jiffies;
+ /* save mtime and size */
+ local_mtime = tmp_inode->i_mtime;
+ local_size = tmp_inode->i_size;
+
/* Linux can not store file creation time unfortunately so ignore it */
tmp_inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
@@ -134,7 +141,6 @@ static void fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_mode = cifs_sb->mnt_file_mode;
}
- cFYI(0,("CIFS FFIRST: Attributes came in as 0x%x",attr));
if (attr & ATTR_DIRECTORY) {
*pobject_type = DT_DIR;
/* override default perms since we do not lock dirs */
@@ -175,30 +181,46 @@ static void fill_in_inode(struct inode *tmp_inode,
(unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
tmp_inode->i_blksize));
if (S_ISREG(tmp_inode->i_mode)) {
- cFYI(1, (" File inode "));
+ cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
tmp_inode->i_fop = &cifs_file_direct_ops;
else
tmp_inode->i_fop = &cifs_file_ops;
tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+ if(isNewInode)
+ return; /* No sense invalidating pages for new inode since we
+ have not started caching readahead file data yet */
+
+ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+ (local_size == tmp_inode->i_size)) {
+ cFYI(1, ("inode exists but unchanged"));
+ } else {
+ /* file may have changed on server */
+ cFYI(1, ("invalidate inode, readdir detected change"));
+ invalidate_remote_inode(tmp_inode);
+ }
} else if (S_ISDIR(tmp_inode->i_mode)) {
- cFYI(1, (" Directory inode"));
+ cFYI(1, ("Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
tmp_inode->i_fop = &cifs_dir_ops;
} else if (S_ISLNK(tmp_inode->i_mode)) {
- cFYI(1, (" Symbolic Link inode "));
+ cFYI(1, ("Symbolic Link inode"));
tmp_inode->i_op = &cifs_symlink_inode_ops;
} else {
- cFYI(1, (" Init special inode "));
+ cFYI(1, ("Init special inode"));
init_special_inode(tmp_inode, tmp_inode->i_mode,
tmp_inode->i_rdev);
}
}
static void unix_fill_in_inode(struct inode *tmp_inode,
- FILE_UNIX_INFO *pfindData, int *pobject_type)
+ FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode)
{
+ loff_t local_size;
+ struct timespec local_mtime;
+
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
@@ -208,6 +230,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
cifsInfo->time = jiffies;
atomic_inc(&cifsInfo->inUse);
+ /* save mtime and size */
+ local_mtime = tmp_inode->i_mtime;
+ local_size = tmp_inode->i_size;
+
tmp_inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
tmp_inode->i_mtime =
@@ -265,6 +291,19 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
else
tmp_inode->i_fop = &cifs_file_ops;
tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+ if(isNewInode)
+ return; /* No sense invalidating pages for new inode since we
+ have not started caching readahead file data yet */
+
+ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+ (local_size == tmp_inode->i_size)) {
+ cFYI(1, ("inode exists but unchanged"));
+ } else {
+ /* file may have changed on server */
+ cFYI(1, ("invalidate inode, readdir detected change"));
+ invalidate_remote_inode(tmp_inode);
+ }
} else if (S_ISDIR(tmp_inode->i_mode)) {
cFYI(1, ("Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
@@ -314,15 +353,16 @@ static int initiate_cifs_search(const int xid, struct file *file)
return -EINVAL;
down(&file->f_dentry->d_sb->s_vfs_rename_sem);
- full_path = build_wildcard_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_dentry);
up(&file->f_dentry->d_sb->s_vfs_rename_sem);
if(full_path == NULL) {
return -ENOMEM;
}
- cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
+ cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));
+ffirst_retry:
/* test for Unix extensions */
if (pTcon->ses->capabilities & CAP_UNIX) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
@@ -332,10 +372,16 @@ static int initiate_cifs_search(const int xid, struct file *file)
cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
}
- rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
- &cifsFile->netfid, &cifsFile->srch_inf);
+ rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
+ &cifsFile->netfid, &cifsFile->srch_inf,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if(rc == 0)
cifsFile->invalidHandle = FALSE;
+ if((rc == -EOPNOTSUPP) &&
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+ goto ffirst_retry;
+ }
kfree(full_path);
return rc;
}
@@ -363,10 +409,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
/* validate that new_entry is not past end of SMB */
if(new_entry >= end_of_smb) {
- cFYI(1,("search entry %p began after end of SMB %p old entry %p",
- new_entry,end_of_smb,old_entry));
+ cERROR(1,
+ ("search entry %p began after end of SMB %p old entry %p",
+ new_entry, end_of_smb, old_entry));
return NULL;
- } else
+ } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
+ cERROR(1,("search entry %p extends after end of SMB %p",
+ new_entry, end_of_smb));
+ return NULL;
+ } else
return new_entry;
}
@@ -594,7 +645,12 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
if(unicode) {
/* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */
- pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt);
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ pqst->len = cifs_convertUCSpath((char *)pqst->name,
+ (__le16 *)filename, len/2, nlt);
+ else
+ pqst->len = cifs_strfromUCS_le((char *)pqst->name,
+ (wchar_t *)filename,len/2,nlt);
} else {
pqst->name = filename;
pqst->len = len;
@@ -654,10 +710,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
insert_inode_hash(tmp_inode);
}
+ /* we pass in rc below, indicating whether it is a new inode,
+ so we can figure out whether to invalidate the inode cached
+ data if the file has changed */
if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
- unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type);
+ unix_fill_in_inode(tmp_inode,
+ (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
} else {
- fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type);
+ fill_in_inode(tmp_inode,
+ (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
}
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
@@ -823,7 +884,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start);
- tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL);
+ /* To be safe - for UCS to UTF-8 with strings loaded
+ with the rare long characters alloc more to account for
+ such multibyte target UTF-8 characters. cifs_unicode.c,
+ which actually does the conversion, has the same limit */
+ tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
for(i=0;(i<num_to_fill) && (rc == 0);i++) {
if(current_entry == NULL) {
/* evaluate whether this case is an error */
@@ -832,19 +897,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break;
}
- /* BB FIXME - need to enable the below code BB */
-
- /* if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) ||
- (cifsFile->srch_inf.info_level !=
- something that supports server inodes)) {
- create dentry
- create inode
- fill in inode new_inode (getting local i_ino)
- }
- also create local inode for performance reasons (so we
- have a cache of inode metadata) unless this new mount
- parm says otherwise */
-
rc = cifs_filldir(current_entry, file,
filldir, direntry,tmp_buf);
file->f_pos++;
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h
index e21f1384661f..cd41c67ff8d3 100644
--- a/fs/cifs/smberr.h
+++ b/fs/cifs/smberr.h
@@ -22,94 +22,159 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define SUCCESS 0 /* The request was successful. */
-#define ERRDOS 0x01 /* Error is from the core DOS operating system set */
-#define ERRSRV 0x02 /* Error is generated by the file server daemon */
-#define ERRHRD 0x03 /* Error is a hardware error. */
-#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+#define SUCCESS 0x00 /* The request was successful. */
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set */
+#define ERRSRV 0x02 /* Error is generated by the file server daemon */
+#define ERRHRD 0x03 /* Error is a hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
/* The following error codes may be generated with the SUCCESS error class.*/
-#define SUCCESS 0 /* The request was successful. */
+/*#define SUCCESS 0 The request was successful. */
/* The following error codes may be generated with the ERRDOS error class.*/
-#define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */
-#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */
-#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */
-#define ERRnofids 4 /* Too many open files. The server has no file handles available. */
-#define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */
-#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */
-#define ERRbadmcb 7 /* Memory control blocks destroyed. */
-#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */
-#define ERRbadmem 9 /* Invalid memory block address. */
-#define ERRbadenv 10 /* Invalid environment. */
-#define ERRbadformat 11 /* Invalid format. */
-#define ERRbadaccess 12 /* Invalid open mode. */
-#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */
-#define ERRbaddrive 15 /* Invalid drive specified. */
-#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */
-#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */
-#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */
-#define ERRgeneral 31
-#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */
-#define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */
-#define ERRunsup 50
-#define ERRnosuchshare 67
-#define ERRfilexists 80 /* The file named in the request already exists. */
-#define ERRinvparm 87
-#define ERRdiskfull 112
-#define ERRinvname 123
-#define ERRinvlevel 124
-#define ERRdirnotempty 145
-#define ERRnotlocked 158
-#define ERRalreadyexists 183
-#define ERRbadpipe 230
-#define ERRpipebusy 231
-#define ERRpipeclosing 232
-#define ERRnotconnected 233
-#define ERRmoredata 234
-#define ERReasnotsupported 282
-#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */
-#define ErrNotALink 0x201 /* A link operation was performed on a pathname that
- was not a link. */
+#define ERRbadfunc 1 /* Invalid function. The server did not
+ recognize or could not perform a
+ system call generated by the server,
+ e.g., set the DIRECTORY attribute on
+ a data file, invalid seek mode. */
+#define ERRbadfile 2 /* File not found. The last component
+ of a file's pathname could not be
+ found. */
+#define ERRbadpath 3 /* Directory invalid. A directory
+ component in a pathname could not be
+ found. */
+#define ERRnofids 4 /* Too many open files. The server has
+ no file handles available. */
+#define ERRnoaccess 5 /* Access denied, the client's context
+ does not permit the requested
+ function. This includes the
+ following conditions: invalid rename
+ command, write to Fid open for read
+ only, read on Fid open for write
+ only, attempt to delete a non-empty
+ directory */
+#define ERRbadfid 6 /* Invalid file handle. The file handle
+ specified was not recognized by the
+ server. */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Insufficient server memory to
+ perform the requested function. */
+#define ERRbadmem 9 /* Invalid memory block address. */
+#define ERRbadenv 10 /* Invalid environment. */
+#define ERRbadformat 11 /* Invalid format. */
+#define ERRbadaccess 12 /* Invalid open mode. */
+#define ERRbaddata 13 /* Invalid data (generated only by
+ IOCTL calls within the server). */
+#define ERRbaddrive 15 /* Invalid drive specified. */
+#define ERRremcd 16 /* A Delete Directory request attempted
+ to remove the server's current
+ directory. */
+#define ERRdiffdevice 17 /* Not same device (e.g., a cross
+ volume rename was attempted */
+#define ERRnofiles 18 /* A File Search command can find no
+ more files matching the specified
+ criteria. */
+#define ERRgeneral 31
+#define ERRbadshare 32 /* The sharing mode specified for an
+ Open conflicts with existing FIDs on
+ the file. */
+#define ERRlock 33 /* A Lock request conflicted with an
+ existing lock or specified an
+ invalid mode, or an Unlock requested
+ attempted to remove a lock held by
+ another process. */
+#define ERRunsup 50
+#define ERRnosuchshare 67
+#define ERRfilexists 80 /* The file named in the request
+ already exists. */
+#define ERRinvparm 87
+#define ERRdiskfull 112
+#define ERRinvname 123
+#define ERRinvlevel 124
+#define ERRdirnotempty 145
+#define ERRnotlocked 158
+#define ERRalreadyexists 183
+#define ERRbadpipe 230
+#define ERRpipebusy 231
+#define ERRpipeclosing 232
+#define ERRnotconnected 233
+#define ERRmoredata 234
+#define ERReasnotsupported 282
+#define ErrQuota 0x200 /* The operation would cause a quota
+ limit to be exceeded. */
+#define ErrNotALink 0x201 /* A link operation was performed on a
+ pathname that was not a link. */
-/* Following error codes may be generated with the ERRSRV error
-class.*/
+/* Below errors are used internally (do not come over the wire) for passthrough
+ from STATUS codes to POSIX only */
+#define ErrTooManyLinks 0xFFFE
-#define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */
-#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */
-#define ERRbadtype 3 /* used for indicating DFS referral needed */
-#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */
-#define ERRinvtid 5 /* The Tid specified in a command was invalid. */
-#define ERRinvnetname 6 /* Invalid network name in tree connect. */
-#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */
-#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */
-#define ERRqtoobig 50 /* Print queue full -- no space. */
-#define ERRqeof 51 /* EOF on print queue dump */
-#define ERRinvpfid 52 /* Invalid print file FID. */
-#define ERRsmbcmd 64 /* The server did not recognize the command received. */
-#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */
-#define ERRbadBID 66 /* (obsolete) */
-#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */
-#define ERRbadLink 68 /* (obsolete) */
-#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */
-#define ERRbadPID 70
-#define ERRsetattrmode 71 /* attribute (mode) is invalid */
-#define ERRpaused 81 /* Server is paused */
-#define ERRmsgoff 82 /* reserved - messaging off */
-#define ERRnoroom 83 /* reserved - no room for message */
-#define ERRrmuns 87 /* reserved - too many remote names */
-#define ERRtimeout 88 /* operation timed out */
-#define ERRnoresource 89 /* No resources available for request */
-#define ERRtoomanyuids 90 /* Too many UIDs active on this session */
-#define ERRbaduid 91 /* The UID is not known as a valid user */
-#define ERRusempx 250 /* temporarily unable to use raw */
-#define ERRusestd 251 /* temporarily unable to use either raw or mpx */
-#define ERR_NOTIFY_ENUM_DIR 1024
-#define ERRaccountexpired 2239
-#define ERRbadclient 2240
-#define ERRbadLogonTime 2241
-#define ERRpasswordExpired 2242
-#define ERRnetlogonNotStarted 2455
-#define ERRnosupport 0xFFFF
+/* Following error codes may be generated with the ERRSRV error class.*/
+
+#define ERRerror 1 /* Non-specific error code. It is
+ returned under the following
+ conditions: resource other than disk
+ space exhausted (e.g. TIDs), first
+ SMB command was not negotiate,
+ multiple negotiates attempted, and
+ internal server error. */
+#define ERRbadpw 2 /* Bad password - name/password pair in
+ a TreeConnect or Session Setup are
+ invalid. */
+#define ERRbadtype 3 /* used for indicating DFS referral
+ needed */
+#define ERRaccess 4 /* The client does not have the
+ necessary access rights within the
+ specified context for requested
+ function. */
+#define ERRinvtid 5 /* The Tid specified in a command was
+ invalid. */
+#define ERRinvnetname 6 /* Invalid network name in tree
+ connect. */
+#define ERRinvdevice 7 /* Invalid device - printer request
+ made to non-printer connection or
+ non-printer request made to printer
+ connection. */
+#define ERRqfull 49 /* Print queue full (files) -- returned
+ by open print file. */
+#define ERRqtoobig 50 /* Print queue full -- no space. */
+#define ERRqeof 51 /* EOF on print queue dump */
+#define ERRinvpfid 52 /* Invalid print file FID. */
+#define ERRsmbcmd 64 /* The server did not recognize the
+ command received. */
+#define ERRsrverror 65 /* The server encountered an internal
+ error, e.g., system file
+ unavailable. */
+#define ERRbadBID 66 /* (obsolete) */
+#define ERRfilespecs 67 /* The Fid and pathname parameters
+ contained an invalid combination of
+ values. */
+#define ERRbadLink 68 /* (obsolete) */
+#define ERRbadpermits 69 /* The access permissions specified for
+ a file or directory are not a valid
+ combination. */
+#define ERRbadPID 70
+#define ERRsetattrmode 71 /* attribute (mode) is invalid */
+#define ERRpaused 81 /* Server is paused */
+#define ERRmsgoff 82 /* reserved - messaging off */
+#define ERRnoroom 83 /* reserved - no room for message */
+#define ERRrmuns 87 /* reserved - too many remote names */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources available for request
+ */
+#define ERRtoomanyuids 90 /* Too many UIDs active on this session
+ */
+#define ERRbaduid 91 /* The UID is not known as a valid user
+ */
+#define ERRusempx 250 /* temporarily unable to use raw */
+#define ERRusestd 251 /* temporarily unable to use either raw
+ or mpx */
+#define ERR_NOTIFY_ENUM_DIR 1024
+#define ERRaccountexpired 2239
+#define ERRbadclient 2240
+#define ERRbadLogonTime 2241
+#define ERRpasswordExpired 2242
+#define ERRnetlogonNotStarted 2455
+#define ERRnosupport 0xFFFF
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index af13e526b150..0046c219833d 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/transport.c
*
- * Copyright (C) International Business Machines Corp., 2002,2004
+ * Copyright (C) International Business Machines Corp., 2002,2005
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
struct mid_q_entry *temp;
if (ses == NULL) {
- cERROR(1, ("Null session passed in to AllocMidQEntry "));
+ cERROR(1, ("Null session passed in to AllocMidQEntry"));
return NULL;
}
if (ses->server == NULL) {
@@ -79,7 +79,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
list_del(&midEntry->qhead);
atomic_dec(&midCount);
spin_unlock(&GlobalMid_Lock);
- cifs_buf_release(midEntry->resp_buf);
+ if(midEntry->largeBuf)
+ cifs_buf_release(midEntry->resp_buf);
+ else
+ cifs_small_buf_release(midEntry->resp_buf);
mempool_free(midEntry, cifs_mid_poolp);
}
@@ -182,14 +185,14 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
int
smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
- unsigned int smb_buf_length, struct kvec * write_vector /* page list */, struct sockaddr *sin)
+ unsigned int smb_buf_length, struct kvec * write_vector
+ /* page list */, struct sockaddr *sin)
{
int rc = 0;
int i = 0;
struct msghdr smb_msg;
number_of_pages += 1; /* account for SMB header */
struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec));
- if(i=0;i<num_pages-1;i++
unsigned len = smb_buf_length + 4;
if(ssocket == NULL)
@@ -213,7 +216,8 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
dump_smb(smb_buffer, len);
while (len > 0) {
- rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, len?);
+ rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages,
+ len);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
i++;
if(i > 60) {
@@ -266,6 +270,9 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
+ if(ses->server->tcpStatus == CIFS_EXITING)
+ return -ENOENT;
+
/* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
@@ -346,11 +353,12 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
}
/* BB can we sign efficiently in this path? */
- rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+ rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED;
-/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
- (struct sockaddr *) &(ses->server->addr.sockAddr));*/
+/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+ piovec,
+ (struct sockaddr *) &(ses->server->addr.sockAddr));*/
if(rc < 0) {
DeleteMidQEntry(midQ);
up(&ses->server->tcpSem);
@@ -396,6 +404,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return -EIO;
}
+ if(ses->server->tcpStatus == CifsExiting)
+ return -ENOENT;
+
/* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
@@ -405,7 +416,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} else {
spin_lock(&GlobalMid_Lock);
while(1) {
- if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
+ if(atomic_read(&ses->server->inFlight) >=
+ cifs_max_pending){
spin_unlock(&GlobalMid_Lock);
wait_event(ses->server->request_q,
atomic_read(&ses->server->inFlight)
@@ -475,7 +487,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return -EIO;
}
- rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+ rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED;
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
@@ -493,7 +505,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
up(&ses->server->tcpSem);
if (long_op == -1)
goto cifs_no_response_exit;
- else if (long_op == 2) /* writes past end of file can take looooong time */
+ else if (long_op == 2) /* writes past end of file can take loong time */
timeout = 300 * HZ;
else if (long_op == 1)
timeout = 45 * HZ; /* should be greater than
@@ -559,8 +571,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
}
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
- cERROR(1,
- ("Frame too large received. Length: %d Xid: %d",
+ cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
rc = -EIO;
} else { /* rcvd frame is ok */
@@ -575,15 +586,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
dump_smb(out_buf, 92);
/* convert the length into a more usable form */
if((receive_len > 24) &&
- (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
- rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
- if(rc)
- cFYI(1,("Unexpected signature received from server"));
+ (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+ SECMODE_SIGN_ENABLED))) {
+ rc = cifs_verify_signature(out_buf,
+ ses->server->mac_signing_key,
+ midQ->sequence_number+1);
+ if(rc) {
+ cERROR(1,("Unexpected SMB signature"));
+ /* BB FIXME add code to kill session */
+ }
}
*pbytes_returned = out_buf->smb_buf_length;
- /* BB special case reconnect tid and reconnect uid here? */
+ /* BB special case reconnect tid and uid here? */
rc = map_smb_to_linux_error(out_buf);
/* convert ByteCount if necessary */
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 549afa184fd6..c1e02eff1d25 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -83,7 +83,8 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
ea_name+=5; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL,
- (__u16)0, cifs_sb->local_nls);
+ (__u16)0, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
}
remove_ea_exit:
if (full_path)
@@ -147,32 +148,40 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
}
ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
- (__u16)value_size, cifs_sb->local_nls);
+ (__u16)value_size, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit;
ea_name += 4; /* skip past os2. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
- (__u16)value_size, cifs_sb->local_nls);
+ (__u16)value_size, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
int temp;
temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS));
if (temp == 0) {
#ifdef CONFIG_CIFS_POSIX
- rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
- (const int)value_size, ACL_TYPE_ACCESS,
- cifs_sb->local_nls);
+ if(sb->s_flags & MS_POSIXACL)
+ rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
+ ea_value, (const int)value_size,
+ ACL_TYPE_ACCESS,cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("set POSIX ACL rc %d",rc));
#else
cFYI(1,("set POSIX ACL not supported"));
#endif
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
- rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
- (const int)value_size, ACL_TYPE_DEFAULT,
- cifs_sb->local_nls);
+ if(sb->s_flags & MS_POSIXACL)
+ rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
+ ea_value, (const int)value_size,
+ ACL_TYPE_DEFAULT, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("set POSIX default ACL rc %d",rc));
#else
cFYI(1,("set default POSIX ACL not supported"));
@@ -238,27 +247,35 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
} /* BB add else when above is implemented */
ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
- buf_size, cifs_sb->local_nls);
+ buf_size, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit;
ea_name += 4; /* skip past os2. prefix */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
- buf_size, cifs_sb->local_nls);
+ buf_size, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX
- rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+ if(sb->s_flags & MS_POSIXACL)
+ rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_ACCESS,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
#else
cFYI(1,("query POSIX ACL not supported yet"));
#endif /* CONFIG_CIFS_POSIX */
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
- rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+ if(sb->s_flags & MS_POSIXACL)
+ rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_DEFAULT,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
#else
cFYI(1,("query POSIX default ACL not supported yet"));
#endif
@@ -324,7 +341,9 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
search server for EAs or streams to
returns as xattrs */
rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size,
- cifs_sb->local_nls);
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (full_path)
kfree(full_path);
diff --git a/fs/compat.c b/fs/compat.c
index 67c0b94d1148..728cd8365384 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -809,7 +809,7 @@ static void *do_smb_super_data_conv(void *raw_data)
struct compat_nfs_string {
compat_uint_t len;
- compat_uptr_t __user data;
+ compat_uptr_t data;
};
static inline void compat_nfs_string(struct nfs_string *dst,
@@ -834,10 +834,10 @@ struct compat_nfs4_mount_data_v1 {
struct compat_nfs_string mnt_path;
struct compat_nfs_string hostname;
compat_uint_t host_addrlen;
- compat_uptr_t __user host_addr;
+ compat_uptr_t host_addr;
compat_int_t proto;
compat_int_t auth_flavourlen;
- compat_uptr_t __user auth_flavours;
+ compat_uptr_t auth_flavours;
};
static int do_nfs4_super_data_conv(void *raw_data)
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 040eb288bb1c..ea5888688f94 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -455,12 +455,11 @@ static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
* @goal: place to store the result.
*
* Normally this function find the prefered place for block allocation,
- * stores it in *@goal and returns zero. If the branch had been changed
- * under us we return -EAGAIN.
+ * stores it in *@goal and returns zero.
*/
-static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4],
- Indirect *partial, unsigned long *goal)
+static unsigned long ext3_find_goal(struct inode *inode, long block,
+ Indirect chain[4], Indirect *partial)
{
struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info;
@@ -470,15 +469,10 @@ static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4],
*/
if (block_i && (block == block_i->last_alloc_logical_block + 1)
&& (block_i->last_alloc_physical_block != 0)) {
- *goal = block_i->last_alloc_physical_block + 1;
- return 0;
+ return block_i->last_alloc_physical_block + 1;
}
- if (verify_chain(chain, partial)) {
- *goal = ext3_find_near(inode, partial);
- return 0;
- }
- return -EAGAIN;
+ return ext3_find_near(inode, partial);
}
/**
@@ -582,12 +576,9 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
* @where: location of missing link
* @num: number of blocks we are adding
*
- * This function verifies that chain (up to the missing link) had not
- * changed, fills the missing link and does all housekeeping needed in
+ * This function fills the missing link and does all housekeeping needed in
* inode (->i_blocks, etc.). In case of success we end up with the full
- * chain to new block and return 0. Otherwise (== chain had been changed)
- * we free the new blocks (forgetting their buffer_heads, indeed) and
- * return -EAGAIN.
+ * chain to new block and return 0.
*/
static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
@@ -608,12 +599,6 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
if (err)
goto err_out;
}
- /* Verify that place we are splicing to is still there and vacant */
-
- if (!verify_chain(chain, where-1) || *where->p)
- /* Writer: end */
- goto changed;
-
/* That's it */
*where->p = where->key;
@@ -657,26 +642,11 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block,
}
return err;
-changed:
- /*
- * AKPM: if where[i].bh isn't part of the current updating
- * transaction then we explode nastily. Test this code path.
- */
- jbd_debug(1, "the chain changed: try again\n");
- err = -EAGAIN;
-
err_out:
for (i = 1; i < num; i++) {
BUFFER_TRACE(where[i].bh, "call journal_forget");
ext3_journal_forget(handle, where[i].bh);
}
- /* For the normal collision cleanup case, we free up the blocks.
- * On genuine filesystem errors we don't even think about doing
- * that. */
- if (err == -EAGAIN)
- for (i = 0; i < num; i++)
- ext3_free_blocks(handle, inode,
- le32_to_cpu(where[i].key), 1);
return err;
}
@@ -708,7 +678,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
unsigned long goal;
int left;
int boundary = 0;
- int depth = ext3_block_to_path(inode, iblock, offsets, &boundary);
+ const int depth = ext3_block_to_path(inode, iblock, offsets, &boundary);
struct ext3_inode_info *ei = EXT3_I(inode);
J_ASSERT(handle != NULL || create == 0);
@@ -716,54 +686,55 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
if (depth == 0)
goto out;
-reread:
partial = ext3_get_branch(inode, depth, offsets, chain, &err);
/* Simplest case - block found, no allocation needed */
if (!partial) {
clear_buffer_new(bh_result);
-got_it:
- map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
- if (boundary)
- set_buffer_boundary(bh_result);
- /* Clean up and exit */
- partial = chain+depth-1; /* the whole chain */
- goto cleanup;
+ goto got_it;
}
/* Next simple case - plain lookup or failed read of indirect block */
- if (!create || err == -EIO) {
-cleanup:
+ if (!create || err == -EIO)
+ goto cleanup;
+
+ down(&ei->truncate_sem);
+
+ /*
+ * If the indirect block is missing while we are reading
+ * the chain(ext3_get_branch() returns -EAGAIN err), or
+ * if the chain has been changed after we grab the semaphore,
+ * (either because another process truncated this branch, or
+ * another get_block allocated this branch) re-grab the chain to see if
+ * the request block has been allocated or not.
+ *
+ * Since we already block the truncate/other get_block
+ * at this point, we will have the current copy of the chain when we
+ * splice the branch into the tree.
+ */
+ if (err == -EAGAIN || !verify_chain(chain, partial)) {
while (partial > chain) {
- BUFFER_TRACE(partial->bh, "call brelse");
brelse(partial->bh);
partial--;
}
- BUFFER_TRACE(bh_result, "returned");
-out:
- return err;
+ partial = ext3_get_branch(inode, depth, offsets, chain, &err);
+ if (!partial) {
+ up(&ei->truncate_sem);
+ if (err)
+ goto cleanup;
+ clear_buffer_new(bh_result);
+ goto got_it;
+ }
}
/*
- * Indirect block might be removed by truncate while we were
- * reading it. Handling of that case (forget what we've got and
- * reread) is taken out of the main path.
- */
- if (err == -EAGAIN)
- goto changed;
-
- goal = 0;
- down(&ei->truncate_sem);
-
- /* lazy initialize the block allocation info here if necessary */
- if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) {
+ * Okay, we need to do block allocation. Lazily initialize the block
+ * allocation info here if necessary
+ */
+ if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
ext3_init_block_alloc_info(inode);
- }
- if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) {
- up(&ei->truncate_sem);
- goto changed;
- }
+ goal = ext3_find_goal(inode, iblock, chain, partial);
left = (chain + depth) - partial;
@@ -771,38 +742,45 @@ out:
* Block out ext3_truncate while we alter the tree
*/
err = ext3_alloc_branch(handle, inode, left, goal,
- offsets+(partial-chain), partial);
+ offsets + (partial - chain), partial);
- /* The ext3_splice_branch call will free and forget any buffers
+ /*
+ * The ext3_splice_branch call will free and forget any buffers
* on the new chain if there is a failure, but that risks using
* up transaction credits, especially for bitmaps where the
* credits cannot be returned. Can we handle this somehow? We
- * may need to return -EAGAIN upwards in the worst case. --sct */
+ * may need to return -EAGAIN upwards in the worst case. --sct
+ */
if (!err)
err = ext3_splice_branch(handle, inode, iblock, chain,
partial, left);
- /* i_disksize growing is protected by truncate_sem
- * don't forget to protect it if you're about to implement
- * concurrent ext3_get_block() -bzzz */
+ /*
+ * i_disksize growing is protected by truncate_sem. Don't forget to
+ * protect it if you're about to implement concurrent
+ * ext3_get_block() -bzzz
+ */
if (!err && extend_disksize && inode->i_size > ei->i_disksize)
ei->i_disksize = inode->i_size;
up(&ei->truncate_sem);
- if (err == -EAGAIN)
- goto changed;
if (err)
goto cleanup;
set_buffer_new(bh_result);
- goto got_it;
-
-changed:
+got_it:
+ map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
+ if (boundary)
+ set_buffer_boundary(bh_result);
+ /* Clean up and exit */
+ partial = chain + depth - 1; /* the whole chain */
+cleanup:
while (partial > chain) {
- jbd_debug(1, "buffer chain changed, retrying\n");
- BUFFER_TRACE(partial->bh, "brelsing");
+ BUFFER_TRACE(partial->bh, "call brelse");
brelse(partial->bh);
partial--;
}
- goto reread;
+ BUFFER_TRACE(bh_result, "returned");
+out:
+ return err;
}
static int ext3_get_block(struct inode *inode, sector_t iblock,
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 3e7ab16ed154..286a9f8f3d49 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/security.h>
#include <linux/ptrace.h>
+#include <linux/signal.h>
#include <asm/poll.h>
#include <asm/siginfo.h>
@@ -308,7 +309,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
break;
case F_SETSIG:
/* arg == 0 restores default behaviour. */
- if (arg < 0 || arg > _NSIG) {
+ if (!valid_signal(arg)) {
break;
}
err = 0;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index d6efb36cab2a..8e050fa58218 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -512,7 +512,8 @@ restart:
}
/**
- * sync_inodes
+ * sync_inodes - writes all inodes to disk
+ * @wait: wait for completion
*
* sync_inodes() goes through each super block's dirty inode list, writes the
* inodes out, waits on the writeout and puts the inodes back on the normal
@@ -604,6 +605,7 @@ EXPORT_SYMBOL(sync_inode);
/**
* generic_osync_inode - flush all dirty data for a given inode to disk
* @inode: inode to write
+ * @mapping: the address_space that should be flushed
* @what: what to write and wait upon
*
* This can be called by file_write functions for files which have the
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index 4efb640c4d0c..217e32f37e0b 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -333,6 +333,8 @@ void hfs_mdb_close(struct super_block *sb)
* Release the resources associated with the in-core MDB. */
void hfs_mdb_put(struct super_block *sb)
{
+ if (!HFS_SB(sb))
+ return;
/* free the B-trees */
hfs_btree_close(HFS_SB(sb)->ext_tree);
hfs_btree_close(HFS_SB(sb)->cat_tree);
@@ -340,4 +342,7 @@ void hfs_mdb_put(struct super_block *sb)
/* free the buffers holding the primary and alternate MDBs */
brelse(HFS_SB(sb)->mdb_bh);
brelse(HFS_SB(sb)->alt_mdb_bh);
+
+ kfree(HFS_SB(sb));
+ sb->s_fs_info = NULL;
}
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 1e2c193134cc..ab783f6afa3b 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -297,7 +297,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
res = -EINVAL;
if (!parse_options((char *)data, sbi)) {
hfs_warn("hfs_fs: unable to parse mount options.\n");
- goto bail3;
+ goto bail;
}
sb->s_op = &hfs_super_operations;
@@ -310,7 +310,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
hfs_mdb_name(sb));
res = -EINVAL;
- goto bail2;
+ goto bail;
}
/* try to get the root inode */
@@ -340,10 +340,8 @@ bail_iput:
iput(root_inode);
bail_no_root:
hfs_warn("hfs_fs: get root inode failed.\n");
+bail:
hfs_mdb_put(sb);
-bail2:
-bail3:
- kfree(sbi);
return res;
}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 5f8044664a3c..d55ad67b8e42 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -208,7 +208,9 @@ static void hfsplus_write_super(struct super_block *sb)
static void hfsplus_put_super(struct super_block *sb)
{
dprint(DBG_SUPER, "hfsplus_put_super\n");
- if (!(sb->s_flags & MS_RDONLY)) {
+ if (!sb->s_fs_info)
+ return;
+ if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) {
struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
vhdr->modify_date = hfsp_now2mt();
@@ -226,6 +228,8 @@ static void hfsplus_put_super(struct super_block *sb)
brelse(HFSPLUS_SB(sb).s_vhbh);
if (HFSPLUS_SB(sb).nls)
unload_nls(HFSPLUS_SB(sb).nls);
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
}
static int hfsplus_statfs(struct super_block *sb, struct kstatfs *buf)
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index a88ad2924851..e6c63d9cac7b 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -521,7 +521,7 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
static struct address_space_operations hostfs_aops = {
.writepage = hostfs_writepage,
.readpage = hostfs_readpage,
-/* .set_page_dirty = __set_page_dirty_nobuffers, */
+ .set_page_dirty = __set_page_dirty_nobuffers,
.prepare_write = hostfs_prepare_write,
.commit_write = hostfs_commit_write
};
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 0c607c1388f4..771a554701d6 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -79,8 +79,7 @@ static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
- if (!PageLocked(pg))
- PAGE_BUG(pg);
+ BUG_ON(!PageLocked(pg));
pg_buf = kmap(pg);
/* FIXME: Can kmap fail? */
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 7bc906677b0d..24a689179af2 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -175,31 +175,22 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks,
{
s64 lblock64 = lblock;
int rc = 0;
- int take_locks;
xad_t xad;
s64 xaddr;
int xflag;
- s32 xlen;
-
- /*
- * If this is a special inode (imap, dmap)
- * the lock should already be taken
- */
- take_locks = (JFS_IP(ip)->fileset != AGGREGATE_I);
+ s32 xlen = max_blocks;
/*
* Take appropriate lock on inode
*/
- if (take_locks) {
- if (create)
- IWRITE_LOCK(ip);
- else
- IREAD_LOCK(ip);
- }
+ if (create)
+ IWRITE_LOCK(ip);
+ else
+ IREAD_LOCK(ip);
if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
- (xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, 0)
- == 0) && xlen) {
+ (!xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, 0)) &&
+ xaddr) {
if (xflag & XAD_NOTRECORDED) {
if (!create)
/*
@@ -238,7 +229,7 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks,
#ifdef _JFS_4K
if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
goto unlock;
- rc = extAlloc(ip, max_blocks, lblock64, &xad, FALSE);
+ rc = extAlloc(ip, xlen, lblock64, &xad, FALSE);
if (rc)
goto unlock;
@@ -258,12 +249,10 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks,
/*
* Release lock on inode
*/
- if (take_locks) {
- if (create)
- IWRITE_UNLOCK(ip);
- else
- IREAD_UNLOCK(ip);
- }
+ if (create)
+ IWRITE_UNLOCK(ip);
+ else
+ IREAD_UNLOCK(ip);
return rc;
}
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index d86e467c6e42..69007fd546ef 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -471,6 +471,7 @@ dbUpdatePMap(struct inode *ipbmap,
struct metapage *mp;
struct jfs_log *log;
int lsn, difft, diffp;
+ unsigned long flags;
/* the blocks better be within the mapsize. */
if (blkno + nblocks > bmp->db_mapsize) {
@@ -504,6 +505,7 @@ dbUpdatePMap(struct inode *ipbmap,
0);
if (mp == NULL)
return -EIO;
+ metapage_wait_for_io(mp);
}
dp = (struct dmap *) mp->data;
@@ -578,34 +580,32 @@ dbUpdatePMap(struct inode *ipbmap,
if (mp->lsn != 0) {
/* inherit older/smaller lsn */
logdiff(diffp, mp->lsn, log);
+ LOGSYNC_LOCK(log, flags);
if (difft < diffp) {
mp->lsn = lsn;
/* move bp after tblock in logsync list */
- LOGSYNC_LOCK(log);
list_move(&mp->synclist, &tblk->synclist);
- LOGSYNC_UNLOCK(log);
}
/* inherit younger/larger clsn */
- LOGSYNC_LOCK(log);
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
} else {
mp->log = log;
mp->lsn = lsn;
/* insert bp after tblock in logsync list */
- LOGSYNC_LOCK(log);
+ LOGSYNC_LOCK(log, flags);
log->count++;
list_add(&mp->synclist, &tblk->synclist);
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
}
}
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index e357890adfb2..ac41f72d6d50 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -212,7 +212,7 @@ static struct metapage *read_index_page(struct inode *inode, s64 blkno)
s32 xlen;
rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
- if (rc || (xlen == 0))
+ if (rc || (xaddr == 0))
return NULL;
return read_metapage(inode, xaddr, PSIZE, 1);
@@ -231,7 +231,7 @@ static struct metapage *get_index_page(struct inode *inode, s64 blkno)
s32 xlen;
rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
- if (rc || (xlen == 0))
+ if (rc || (xaddr == 0))
return NULL;
return get_metapage(inode, xaddr, PSIZE, 1);
@@ -3181,7 +3181,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
d = (struct ldtentry *) & p->slot[stbl[i]];
if (((long) jfs_dirent + d->namlen + 1) >
- (dirent_buf + PSIZE)) {
+ (dirent_buf + PAGE_SIZE)) {
/* DBCS codepages could overrun dirent_buf */
index = i;
overflow = 1;
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index 783831301625..7acff2ce3c80 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -502,7 +502,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
}
- ip->i_mapping->a_ops = &jfs_aops;
+ ip->i_mapping->a_ops = &jfs_metapage_aops;
mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
/* Allocations to metadata inodes should not affect quotas */
@@ -2573,9 +2573,18 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
goto out;
}
- /* assign a buffer for the page */
- mp = get_metapage(ipimap, xaddr, PSIZE, 1);
- if (!mp) {
+ /*
+ * start transaction of update of the inode map
+ * addressing structure pointing to the new iag page;
+ */
+ tid = txBegin(sb, COMMIT_FORCE);
+ down(&JFS_IP(ipimap)->commit_sem);
+
+ /* update the inode map addressing structure to point to it */
+ if ((rc =
+ xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
+ txEnd(tid);
+ up(&JFS_IP(ipimap)->commit_sem);
/* Free the blocks allocated for the iag since it was
* not successfully added to the inode map
*/
@@ -2584,6 +2593,29 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
/* release the inode map lock */
IWRITE_UNLOCK(ipimap);
+ goto out;
+ }
+
+ /* update the inode map's inode to reflect the extension */
+ ipimap->i_size += PSIZE;
+ inode_add_bytes(ipimap, PSIZE);
+
+ /* assign a buffer for the page */
+ mp = get_metapage(ipimap, blkno, PSIZE, 0);
+ if (!mp) {
+ /*
+ * This is very unlikely since we just created the
+ * extent, but let's try to handle it correctly
+ */
+ xtTruncate(tid, ipimap, ipimap->i_size - PSIZE,
+ COMMIT_PWMAP);
+
+ txAbort(tid, 0);
+ txEnd(tid);
+
+ /* release the inode map lock */
+ IWRITE_UNLOCK(ipimap);
+
rc = -EIO;
goto out;
}
@@ -2605,41 +2637,11 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
iagp->inosmap[i] = cpu_to_le32(ONES);
/*
- * Invalidate the page after writing and syncing it.
- * After it's initialized, we access it in a different
- * address space
+ * Write and sync the metapage
*/
- set_bit(META_discard, &mp->flag);
flush_metapage(mp);
/*
- * start tyransaction of update of the inode map
- * addressing structure pointing to the new iag page;
- */
- tid = txBegin(sb, COMMIT_FORCE);
- down(&JFS_IP(ipimap)->commit_sem);
-
- /* update the inode map addressing structure to point to it */
- if ((rc =
- xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
- txEnd(tid);
- up(&JFS_IP(ipimap)->commit_sem);
- /* Free the blocks allocated for the iag since it was
- * not successfully added to the inode map
- */
- dbFree(ipimap, xaddr, (s64) xlen);
-
- /* release the inode map lock */
- IWRITE_UNLOCK(ipimap);
-
- goto out;
- }
-
- /* update the inode map's inode to reflect the extension */
- ipimap->i_size += PSIZE;
- inode_add_bytes(ipimap, PSIZE);
-
- /*
* txCommit(COMMIT_FORCE) will synchronously write address
* index pages and inode after commit in careful update order
* of address index pages (right to left, bottom up);
@@ -2789,6 +2791,7 @@ diUpdatePMap(struct inode *ipimap,
u32 mask;
struct jfs_log *log;
int lsn, difft, diffp;
+ unsigned long flags;
imap = JFS_IP(ipimap)->i_imap;
/* get the iag number containing the inode */
@@ -2805,6 +2808,7 @@ diUpdatePMap(struct inode *ipimap,
IREAD_UNLOCK(ipimap);
if (rc)
return (rc);
+ metapage_wait_for_io(mp);
iagp = (struct iag *) mp->data;
/* get the inode number and extent number of the inode within
* the iag and the inode number within the extent.
@@ -2868,30 +2872,28 @@ diUpdatePMap(struct inode *ipimap,
/* inherit older/smaller lsn */
logdiff(difft, lsn, log);
logdiff(diffp, mp->lsn, log);
+ LOGSYNC_LOCK(log, flags);
if (difft < diffp) {
mp->lsn = lsn;
/* move mp after tblock in logsync list */
- LOGSYNC_LOCK(log);
list_move(&mp->synclist, &tblk->synclist);
- LOGSYNC_UNLOCK(log);
}
/* inherit younger/larger clsn */
- LOGSYNC_LOCK(log);
assert(mp->clsn);
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
} else {
mp->log = log;
mp->lsn = lsn;
/* insert mp after tblock in logsync list */
- LOGSYNC_LOCK(log);
+ LOGSYNC_LOCK(log, flags);
log->count++;
list_add(&mp->synclist, &tblk->synclist);
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
}
write_metapage(mp);
return (0);
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index ebd77c1bed66..c0fd7b3eadc6 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -165,6 +165,7 @@ struct jfs_sb_info {
/* Formerly in ipbmap */
struct bmap *bmap; /* incore bmap descriptor */
struct nls_table *nls_tab; /* current codepage */
+ struct inode *direct_inode; /* metadata inode */
uint state; /* mount/recovery state */
unsigned long flag; /* mount time flags */
uint p_state; /* state prior to going no integrity */
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index b6a6869ebb4f..dfa1200daa61 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -234,6 +234,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
int lsn;
int diffp, difft;
struct metapage *mp = NULL;
+ unsigned long flags;
jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
log, tblk, lrd, tlck);
@@ -254,7 +255,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
*/
lsn = log->lsn;
- LOGSYNC_LOCK(log);
+ LOGSYNC_LOCK(log, flags);
/*
* initialize page lsn if first log write of the page
@@ -310,7 +311,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
}
}
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
/*
* write the log record
@@ -334,7 +335,6 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
return lsn;
}
-
/*
* NAME: lmWriteRecord()
*
@@ -927,9 +927,8 @@ static void lmPostGC(struct lbuf * bp)
* calculate new value of i_nextsync which determines when
* this code is called again.
*
- * this is called only from lmLog().
- *
- * PARAMETER: ip - pointer to logs inode.
+ * PARAMETERS: log - log structure
+ * nosyncwait - 1 if called asynchronously
*
* RETURN: 0
*
@@ -945,6 +944,15 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait)
struct lrd lrd;
int lsn;
struct logsyncblk *lp;
+ struct jfs_sb_info *sbi;
+ unsigned long flags;
+
+ /* push dirty metapages out to disk */
+ list_for_each_entry(sbi, &log->sb_list, log_list) {
+ filemap_flush(sbi->ipbmap->i_mapping);
+ filemap_flush(sbi->ipimap->i_mapping);
+ filemap_flush(sbi->direct_inode->i_mapping);
+ }
/*
* forward syncpt
@@ -954,10 +962,7 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait)
*/
if (log->sync == log->syncpt) {
- LOGSYNC_LOCK(log);
- /* ToDo: push dirty metapages out to disk */
-// bmLogSync(log);
-
+ LOGSYNC_LOCK(log, flags);
if (list_empty(&log->synclist))
log->sync = log->lsn;
else {
@@ -965,7 +970,7 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait)
struct logsyncblk, synclist);
log->sync = lp->lsn;
}
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
}
@@ -974,27 +979,6 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait)
* reset syncpt = sync
*/
if (log->sync != log->syncpt) {
- struct jfs_sb_info *sbi;
-
- /*
- * We need to make sure all of the "written" metapages
- * actually make it to disk
- */
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- if (sbi->flag & JFS_NOINTEGRITY)
- continue;
- filemap_fdatawrite(sbi->ipbmap->i_mapping);
- filemap_fdatawrite(sbi->ipimap->i_mapping);
- filemap_fdatawrite(sbi->sb->s_bdev->bd_inode->i_mapping);
- }
- list_for_each_entry(sbi, &log->sb_list, log_list) {
- if (sbi->flag & JFS_NOINTEGRITY)
- continue;
- filemap_fdatawait(sbi->ipbmap->i_mapping);
- filemap_fdatawait(sbi->ipimap->i_mapping);
- filemap_fdatawait(sbi->sb->s_bdev->bd_inode->i_mapping);
- }
-
lrd.logtid = 0;
lrd.backchain = 0;
lrd.type = cpu_to_le16(LOG_SYNCPT);
@@ -1066,6 +1050,18 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait)
return lsn;
}
+/*
+ * NAME: jfs_syncpt
+ *
+ * FUNCTION: write log SYNCPT record for specified log
+ *
+ * PARAMETERS: log - log structure
+ */
+void jfs_syncpt(struct jfs_log *log)
+{ LOG_LOCK(log);
+ lmLogSync(log, 1);
+ LOG_UNLOCK(log);
+}
/*
* NAME: lmLogOpen()
@@ -1547,6 +1543,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
{
int i;
struct tblock *target = NULL;
+ struct jfs_sb_info *sbi;
/* jfs_write_inode may call us during read-only mount */
if (!log)
@@ -1608,12 +1605,18 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
if (wait < 2)
return;
+ list_for_each_entry(sbi, &log->sb_list, log_list) {
+ filemap_fdatawrite(sbi->ipbmap->i_mapping);
+ filemap_fdatawrite(sbi->ipimap->i_mapping);
+ filemap_fdatawrite(sbi->direct_inode->i_mapping);
+ }
+
/*
* If there was recent activity, we may need to wait
* for the lazycommit thread to catch up
*/
if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) {
- for (i = 0; i < 800; i++) { /* Too much? */
+ for (i = 0; i < 200; i++) { /* Too much? */
msleep(250);
if (list_empty(&log->cqueue) &&
list_empty(&log->synclist))
@@ -1621,7 +1624,24 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
}
}
assert(list_empty(&log->cqueue));
- assert(list_empty(&log->synclist));
+ if (!list_empty(&log->synclist)) {
+ struct logsyncblk *lp;
+
+ list_for_each_entry(lp, &log->synclist, synclist) {
+ if (lp->xflag & COMMIT_PAGE) {
+ struct metapage *mp = (struct metapage *)lp;
+ dump_mem("orphan metapage", lp,
+ sizeof(struct metapage));
+ dump_mem("page", mp->page, sizeof(struct page));
+ }
+ else
+ dump_mem("orphan tblock", lp,
+ sizeof(struct tblock));
+ }
+// current->state = TASK_INTERRUPTIBLE;
+// schedule();
+ }
+ //assert(list_empty(&log->synclist));
clear_bit(log_FLUSH, &log->flag);
}
@@ -1669,6 +1689,7 @@ int lmLogShutdown(struct jfs_log * log)
lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
lbmIOWait(log->bp, lbmFREE);
+ log->bp = NULL;
/*
* synchronous update log superblock
@@ -1819,20 +1840,34 @@ static int lbmLogInit(struct jfs_log * log)
log->lbuf_free = NULL;
- for (i = 0; i < LOGPAGES; i++) {
- lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
- if (lbuf == 0)
- goto error;
- lbuf->l_ldata = (char *) get_zeroed_page(GFP_KERNEL);
- if (lbuf->l_ldata == 0) {
- kfree(lbuf);
+ for (i = 0; i < LOGPAGES;) {
+ char *buffer;
+ uint offset;
+ struct page *page;
+
+ buffer = (char *) get_zeroed_page(GFP_KERNEL);
+ if (buffer == NULL)
goto error;
+ page = virt_to_page(buffer);
+ for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) {
+ lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
+ if (lbuf == NULL) {
+ if (offset == 0)
+ free_page((unsigned long) buffer);
+ goto error;
+ }
+ if (offset) /* we already have one reference */
+ get_page(page);
+ lbuf->l_offset = offset;
+ lbuf->l_ldata = buffer + offset;
+ lbuf->l_page = page;
+ lbuf->l_log = log;
+ init_waitqueue_head(&lbuf->l_ioevent);
+
+ lbuf->l_freelist = log->lbuf_free;
+ log->lbuf_free = lbuf;
+ i++;
}
- lbuf->l_log = log;
- init_waitqueue_head(&lbuf->l_ioevent);
-
- lbuf->l_freelist = log->lbuf_free;
- log->lbuf_free = lbuf;
}
return (0);
@@ -1857,12 +1892,10 @@ static void lbmLogShutdown(struct jfs_log * log)
lbuf = log->lbuf_free;
while (lbuf) {
struct lbuf *next = lbuf->l_freelist;
- free_page((unsigned long) lbuf->l_ldata);
+ __free_page(lbuf->l_page);
kfree(lbuf);
lbuf = next;
}
-
- log->bp = NULL;
}
@@ -1974,9 +2007,9 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
bio->bi_bdev = log->bdev;
- bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+ bio->bi_io_vec[0].bv_page = bp->l_page;
bio->bi_io_vec[0].bv_len = LOGPSIZE;
- bio->bi_io_vec[0].bv_offset = 0;
+ bio->bi_io_vec[0].bv_offset = bp->l_offset;
bio->bi_vcnt = 1;
bio->bi_idx = 0;
@@ -2115,9 +2148,9 @@ static void lbmStartIO(struct lbuf * bp)
bio = bio_alloc(GFP_NOFS, 1);
bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
bio->bi_bdev = log->bdev;
- bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+ bio->bi_io_vec[0].bv_page = bp->l_page;
bio->bi_io_vec[0].bv_len = LOGPSIZE;
- bio->bi_io_vec[0].bv_offset = 0;
+ bio->bi_io_vec[0].bv_offset = bp->l_offset;
bio->bi_vcnt = 1;
bio->bi_idx = 0;
@@ -2127,16 +2160,13 @@ static void lbmStartIO(struct lbuf * bp)
bio->bi_private = bp;
/* check if journaling to disk has been disabled */
- if (!log->no_integrity) {
+ if (log->no_integrity) {
+ bio->bi_size = 0;
+ lbmIODone(bio, 0, 0);
+ } else {
submit_bio(WRITE_SYNC, bio);
INCREMENT(lmStat.submitted);
}
- else {
- bio->bi_size = 0;
- lbmIODone(bio, 0, 0); /* 2nd argument appears to not be used => 0
- * 3rd argument appears to not be used => 0
- */
- }
}
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
index 141ad74010c9..51291fbc420c 100644
--- a/fs/jfs/jfs_logmgr.h
+++ b/fs/jfs/jfs_logmgr.h
@@ -463,9 +463,10 @@ struct lbuf {
s64 l_blkno; /* 8: log page block number */
caddr_t l_ldata; /* 4: data page */
+ struct page *l_page; /* The page itself */
+ uint l_offset; /* Offset of l_ldata within the page */
wait_queue_head_t l_ioevent; /* 4: i/o done event */
- struct page *l_page; /* The page itself */
};
/* Reuse l_freelist for redrive list */
@@ -489,8 +490,9 @@ struct logsyncblk {
*/
#define LOGSYNC_LOCK_INIT(log) spin_lock_init(&(log)->synclock)
-#define LOGSYNC_LOCK(log) spin_lock(&(log)->synclock)
-#define LOGSYNC_UNLOCK(log) spin_unlock(&(log)->synclock)
+#define LOGSYNC_LOCK(log, flags) spin_lock_irqsave(&(log)->synclock, flags)
+#define LOGSYNC_UNLOCK(log, flags) \
+ spin_unlock_irqrestore(&(log)->synclock, flags)
/* compute the difference in bytes of lsn from sync point */
#define logdiff(diff, lsn, log)\
@@ -506,5 +508,6 @@ extern int lmLogShutdown(struct jfs_log * log);
extern int lmLogInit(struct jfs_log * log);
extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize);
extern void jfs_flush_journal(struct jfs_log * log, int wait);
+extern void jfs_syncpt(struct jfs_log *log);
#endif /* _H_JFS_LOGMGR */
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 4c0a3ac75c08..41bf078dce05 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) International Business Machines Corp., 2000-2003
+ * Copyright (C) International Business Machines Corp., 2000-2005
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
@@ -18,10 +18,11 @@
*/
#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
#include <linux/init.h>
#include <linux/buffer_head.h>
#include <linux/mempool.h>
-#include <linux/delay.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_filsys.h"
@@ -29,8 +30,6 @@
#include "jfs_txnmgr.h"
#include "jfs_debug.h"
-static DEFINE_SPINLOCK(meta_lock);
-
#ifdef CONFIG_JFS_STATISTICS
static struct {
uint pagealloc; /* # of page allocations */
@@ -39,22 +38,8 @@ static struct {
} mpStat;
#endif
-
-#define HASH_BITS 10 /* This makes hash_table 1 4K page */
-#define HASH_SIZE (1 << HASH_BITS)
-static struct metapage **hash_table = NULL;
-static unsigned long hash_order;
-
-
-static inline int metapage_locked(struct metapage *mp)
-{
- return test_bit(META_locked, &mp->flag);
-}
-
-static inline int trylock_metapage(struct metapage *mp)
-{
- return test_and_set_bit(META_locked, &mp->flag);
-}
+#define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)
+#define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag)
static inline void unlock_metapage(struct metapage *mp)
{
@@ -62,26 +47,26 @@ static inline void unlock_metapage(struct metapage *mp)
wake_up(&mp->wait);
}
-static void __lock_metapage(struct metapage *mp)
+static inline void __lock_metapage(struct metapage *mp)
{
DECLARE_WAITQUEUE(wait, current);
-
INCREMENT(mpStat.lockwait);
-
add_wait_queue_exclusive(&mp->wait, &wait);
do {
set_current_state(TASK_UNINTERRUPTIBLE);
if (metapage_locked(mp)) {
- spin_unlock(&meta_lock);
+ unlock_page(mp->page);
schedule();
- spin_lock(&meta_lock);
+ lock_page(mp->page);
}
} while (trylock_metapage(mp));
__set_current_state(TASK_RUNNING);
remove_wait_queue(&mp->wait, &wait);
}
-/* needs meta_lock */
+/*
+ * Must have mp->page locked
+ */
static inline void lock_metapage(struct metapage *mp)
{
if (trylock_metapage(mp))
@@ -92,6 +77,110 @@ static inline void lock_metapage(struct metapage *mp)
static kmem_cache_t *metapage_cache;
static mempool_t *metapage_mempool;
+#define MPS_PER_PAGE (PAGE_CACHE_SIZE >> L2PSIZE)
+
+#if MPS_PER_PAGE > 1
+
+struct meta_anchor {
+ int mp_count;
+ atomic_t io_count;
+ struct metapage *mp[MPS_PER_PAGE];
+};
+#define mp_anchor(page) ((struct meta_anchor *)page->private)
+
+static inline struct metapage *page_to_mp(struct page *page, uint offset)
+{
+ if (!PagePrivate(page))
+ return NULL;
+ return mp_anchor(page)->mp[offset >> L2PSIZE];
+}
+
+static inline int insert_metapage(struct page *page, struct metapage *mp)
+{
+ struct meta_anchor *a;
+ int index;
+ int l2mp_blocks; /* log2 blocks per metapage */
+
+ if (PagePrivate(page))
+ a = mp_anchor(page);
+ else {
+ a = kmalloc(sizeof(struct meta_anchor), GFP_NOFS);
+ if (!a)
+ return -ENOMEM;
+ memset(a, 0, sizeof(struct meta_anchor));
+ page->private = (unsigned long)a;
+ SetPagePrivate(page);
+ kmap(page);
+ }
+
+ if (mp) {
+ l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;
+ index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);
+ a->mp_count++;
+ a->mp[index] = mp;
+ }
+
+ return 0;
+}
+
+static inline void remove_metapage(struct page *page, struct metapage *mp)
+{
+ struct meta_anchor *a = mp_anchor(page);
+ int l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;
+ int index;
+
+ index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);
+
+ BUG_ON(a->mp[index] != mp);
+
+ a->mp[index] = NULL;
+ if (--a->mp_count == 0) {
+ kfree(a);
+ page->private = 0;
+ ClearPagePrivate(page);
+ kunmap(page);
+ }
+}
+
+static inline void inc_io(struct page *page)
+{
+ atomic_inc(&mp_anchor(page)->io_count);
+}
+
+static inline void dec_io(struct page *page, void (*handler) (struct page *))
+{
+ if (atomic_dec_and_test(&mp_anchor(page)->io_count))
+ handler(page);
+}
+
+#else
+static inline struct metapage *page_to_mp(struct page *page, uint offset)
+{
+ return PagePrivate(page) ? (struct metapage *)page->private : NULL;
+}
+
+static inline int insert_metapage(struct page *page, struct metapage *mp)
+{
+ if (mp) {
+ page->private = (unsigned long)mp;
+ SetPagePrivate(page);
+ kmap(page);
+ }
+ return 0;
+}
+
+static inline void remove_metapage(struct page *page, struct metapage *mp)
+{
+ page->private = 0;
+ ClearPagePrivate(page);
+ kunmap(page);
+}
+
+#define inc_io(page) do {} while(0)
+#define dec_io(page, handler) handler(page)
+
+#endif
+
static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
{
struct metapage *mp = (struct metapage *)foo;
@@ -139,16 +228,6 @@ int __init metapage_init(void)
kmem_cache_destroy(metapage_cache);
return -ENOMEM;
}
- /*
- * Now the hash list
- */
- for (hash_order = 0;
- ((PAGE_SIZE << hash_order) / sizeof(void *)) < HASH_SIZE;
- hash_order++);
- hash_table =
- (struct metapage **) __get_free_pages(GFP_KERNEL, hash_order);
- assert(hash_table);
- memset(hash_table, 0, PAGE_SIZE << hash_order);
return 0;
}
@@ -159,73 +238,388 @@ void metapage_exit(void)
kmem_cache_destroy(metapage_cache);
}
+static inline void drop_metapage(struct page *page, struct metapage *mp)
+{
+ if (mp->count || mp->nohomeok || test_bit(META_dirty, &mp->flag) ||
+ test_bit(META_io, &mp->flag))
+ return;
+ remove_metapage(page, mp);
+ INCREMENT(mpStat.pagefree);
+ free_metapage(mp);
+}
+
/*
- * Basically same hash as in pagemap.h, but using our hash table
+ * Metapage address space operations
*/
-static struct metapage **meta_hash(struct address_space *mapping,
- unsigned long index)
+
+static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
+ unsigned int *len)
{
-#define i (((unsigned long)mapping)/ \
- (sizeof(struct inode) & ~(sizeof(struct inode) -1 )))
-#define s(x) ((x) + ((x) >> HASH_BITS))
- return hash_table + (s(i + index) & (HASH_SIZE - 1));
-#undef i
-#undef s
+ int rc = 0;
+ int xflag;
+ s64 xaddr;
+ sector_t file_blocks = (inode->i_size + inode->i_blksize - 1) >>
+ inode->i_blkbits;
+
+ if (lblock >= file_blocks)
+ return 0;
+ if (lblock + *len > file_blocks)
+ *len = file_blocks - lblock;
+
+ if (inode->i_ino) {
+ rc = xtLookup(inode, (s64)lblock, *len, &xflag, &xaddr, len, 0);
+ if ((rc == 0) && *len)
+ lblock = (sector_t)xaddr;
+ else
+ lblock = 0;
+ } /* else no mapping */
+
+ return lblock;
}
-static struct metapage *search_hash(struct metapage ** hash_ptr,
- struct address_space *mapping,
- unsigned long index)
+static void last_read_complete(struct page *page)
{
- struct metapage *ptr;
+ if (!PageError(page))
+ SetPageUptodate(page);
+ unlock_page(page);
+}
+
+static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done,
+ int err)
+{
+ struct page *page = bio->bi_private;
+
+ if (bio->bi_size)
+ return 1;
- for (ptr = *hash_ptr; ptr; ptr = ptr->hash_next) {
- if ((ptr->mapping == mapping) && (ptr->index == index))
- return ptr;
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+ printk(KERN_ERR "metapage_read_end_io: I/O error\n");
+ SetPageError(page);
}
- return NULL;
+ dec_io(page, last_read_complete);
+ bio_put(bio);
+
+ return 0;
}
-static void add_to_hash(struct metapage * mp, struct metapage ** hash_ptr)
+static void remove_from_logsync(struct metapage *mp)
{
- if (*hash_ptr)
- (*hash_ptr)->hash_prev = mp;
+ struct jfs_log *log = mp->log;
+ unsigned long flags;
+/*
+ * This can race. Recheck that log hasn't been set to null, and after
+ * acquiring logsync lock, recheck lsn
+ */
+ if (!log)
+ return;
+
+ LOGSYNC_LOCK(log, flags);
+ if (mp->lsn) {
+ mp->log = NULL;
+ mp->lsn = 0;
+ mp->clsn = 0;
+ log->count--;
+ list_del(&mp->synclist);
+ }
+ LOGSYNC_UNLOCK(log, flags);
+}
- mp->hash_prev = NULL;
- mp->hash_next = *hash_ptr;
- *hash_ptr = mp;
+static void last_write_complete(struct page *page)
+{
+ struct metapage *mp;
+ unsigned int offset;
+
+ for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+ mp = page_to_mp(page, offset);
+ if (mp && test_bit(META_io, &mp->flag)) {
+ if (mp->lsn)
+ remove_from_logsync(mp);
+ clear_bit(META_io, &mp->flag);
+ }
+ /*
+ * I'd like to call drop_metapage here, but I don't think it's
+ * safe unless I have the page locked
+ */
+ }
+ end_page_writeback(page);
}
-static void remove_from_hash(struct metapage * mp, struct metapage ** hash_ptr)
+static int metapage_write_end_io(struct bio *bio, unsigned int bytes_done,
+ int err)
{
- if (mp->hash_prev)
- mp->hash_prev->hash_next = mp->hash_next;
- else {
- assert(*hash_ptr == mp);
- *hash_ptr = mp->hash_next;
+ struct page *page = bio->bi_private;
+
+ BUG_ON(!PagePrivate(page));
+
+ if (bio->bi_size)
+ return 1;
+
+ if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+ printk(KERN_ERR "metapage_write_end_io: I/O error\n");
+ SetPageError(page);
+ }
+ dec_io(page, last_write_complete);
+ bio_put(bio);
+ return 0;
+}
+
+static int metapage_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct bio *bio = NULL;
+ unsigned int block_offset; /* block offset of mp within page */
+ struct inode *inode = page->mapping->host;
+ unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
+ unsigned int len;
+ unsigned int xlen;
+ struct metapage *mp;
+ int redirty = 0;
+ sector_t lblock;
+ sector_t pblock;
+ sector_t next_block = 0;
+ sector_t page_start;
+ unsigned long bio_bytes = 0;
+ unsigned long bio_offset = 0;
+ unsigned int offset;
+
+ page_start = (sector_t)page->index <<
+ (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ BUG_ON(!PageLocked(page));
+ BUG_ON(PageWriteback(page));
+
+ for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+ mp = page_to_mp(page, offset);
+
+ if (!mp || !test_bit(META_dirty, &mp->flag))
+ continue;
+
+ if (mp->nohomeok && !test_bit(META_forcewrite, &mp->flag)) {
+ redirty = 1;
+ continue;
+ }
+
+ clear_bit(META_dirty, &mp->flag);
+ block_offset = offset >> inode->i_blkbits;
+ lblock = page_start + block_offset;
+ if (bio) {
+ if (xlen && lblock == next_block) {
+ /* Contiguous, in memory & on disk */
+ len = min(xlen, blocks_per_mp);
+ xlen -= len;
+ bio_bytes += len << inode->i_blkbits;
+ set_bit(META_io, &mp->flag);
+ continue;
+ }
+ /* Not contiguous */
+ if (bio_add_page(bio, page, bio_bytes, bio_offset) <
+ bio_bytes)
+ goto add_failed;
+ /*
+ * Increment counter before submitting i/o to keep
+ * count from hitting zero before we're through
+ */
+ inc_io(page);
+ if (!bio->bi_size)
+ goto dump_bio;
+ submit_bio(WRITE, bio);
+ bio = NULL;
+ } else {
+ set_page_writeback(page);
+ inc_io(page);
+ }
+ xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
+ pblock = metapage_get_blocks(inode, lblock, &xlen);
+ if (!pblock) {
+ /* Need better error handling */
+ printk(KERN_ERR "JFS: metapage_get_blocks failed\n");
+ dec_io(page, last_write_complete);
+ continue;
+ }
+ set_bit(META_io, &mp->flag);
+ len = min(xlen, (uint) JFS_SBI(inode->i_sb)->nbperpage);
+
+ bio = bio_alloc(GFP_NOFS, 1);
+ bio->bi_bdev = inode->i_sb->s_bdev;
+ bio->bi_sector = pblock << (inode->i_blkbits - 9);
+ bio->bi_end_io = metapage_write_end_io;
+ bio->bi_private = page;
+
+ /* Don't call bio_add_page yet, we may add to this vec */
+ bio_offset = offset;
+ bio_bytes = len << inode->i_blkbits;
+
+ xlen -= len;
+ next_block = lblock + len;
+ }
+ if (bio) {
+ if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes)
+ goto add_failed;
+ if (!bio->bi_size)
+ goto dump_bio;
+
+ submit_bio(WRITE, bio);
+ }
+ if (redirty)
+ redirty_page_for_writepage(wbc, page);
+
+ unlock_page(page);
+
+ return 0;
+add_failed:
+ /* We should never reach here, since we're only adding one vec */
+ printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
+ goto skip;
+dump_bio:
+ dump_mem("bio", bio, sizeof(*bio));
+skip:
+ bio_put(bio);
+ unlock_page(page);
+ dec_io(page, last_write_complete);
+
+ return -EIO;
+}
+
+static int metapage_readpage(struct file *fp, struct page *page)
+{
+ struct inode *inode = page->mapping->host;
+ struct bio *bio = NULL;
+ unsigned int block_offset;
+ unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
+ sector_t page_start; /* address of page in fs blocks */
+ sector_t pblock;
+ unsigned int xlen;
+ unsigned int len;
+ unsigned int offset;
+
+ BUG_ON(!PageLocked(page));
+ page_start = (sector_t)page->index <<
+ (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+ block_offset = 0;
+ while (block_offset < blocks_per_page) {
+ xlen = blocks_per_page - block_offset;
+ pblock = metapage_get_blocks(inode, page_start + block_offset,
+ &xlen);
+ if (pblock) {
+ if (!PagePrivate(page))
+ insert_metapage(page, NULL);
+ inc_io(page);
+ if (bio)
+ submit_bio(READ, bio);
+
+ bio = bio_alloc(GFP_NOFS, 1);
+ bio->bi_bdev = inode->i_sb->s_bdev;
+ bio->bi_sector = pblock << (inode->i_blkbits - 9);
+ bio->bi_end_io = metapage_read_end_io;
+ bio->bi_private = page;
+ len = xlen << inode->i_blkbits;
+ offset = block_offset << inode->i_blkbits;
+ if (bio_add_page(bio, page, len, offset) < len)
+ goto add_failed;
+ block_offset += xlen;
+ } else
+ block_offset++;
}
+ if (bio)
+ submit_bio(READ, bio);
+ else
+ unlock_page(page);
+
+ return 0;
- if (mp->hash_next)
- mp->hash_next->hash_prev = mp->hash_prev;
+add_failed:
+ printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
+ bio_put(bio);
+ dec_io(page, last_read_complete);
+ return -EIO;
}
+static int metapage_releasepage(struct page *page, int gfp_mask)
+{
+ struct metapage *mp;
+ int busy = 0;
+ unsigned int offset;
+
+ for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+ mp = page_to_mp(page, offset);
+
+ if (!mp)
+ continue;
+
+ jfs_info("metapage_releasepage: mp = 0x%p", mp);
+ if (mp->count || mp->nohomeok) {
+ jfs_info("count = %ld, nohomeok = %d", mp->count,
+ mp->nohomeok);
+ busy = 1;
+ continue;
+ }
+ wait_on_page_writeback(page);
+ //WARN_ON(test_bit(META_dirty, &mp->flag));
+ if (test_bit(META_dirty, &mp->flag)) {
+ dump_mem("dirty mp in metapage_releasepage", mp,
+ sizeof(struct metapage));
+ dump_mem("page", page, sizeof(struct page));
+ dump_stack();
+ }
+ WARN_ON(mp->lsn);
+ if (mp->lsn)
+ remove_from_logsync(mp);
+ remove_metapage(page, mp);
+ INCREMENT(mpStat.pagefree);
+ free_metapage(mp);
+ }
+ if (busy)
+ return -1;
+
+ return 0;
+}
+
+static int metapage_invalidatepage(struct page *page, unsigned long offset)
+{
+ BUG_ON(offset);
+
+ if (PageWriteback(page))
+ return 0;
+
+ return metapage_releasepage(page, 0);
+}
+
+struct address_space_operations jfs_metapage_aops = {
+ .readpage = metapage_readpage,
+ .writepage = metapage_writepage,
+ .sync_page = block_sync_page,
+ .releasepage = metapage_releasepage,
+ .invalidatepage = metapage_invalidatepage,
+ .set_page_dirty = __set_page_dirty_nobuffers,
+};
+
struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
unsigned int size, int absolute,
unsigned long new)
{
- struct metapage **hash_ptr;
int l2BlocksPerPage;
int l2bsize;
struct address_space *mapping;
- struct metapage *mp;
+ struct metapage *mp = NULL;
+ struct page *page;
unsigned long page_index;
unsigned long page_offset;
- jfs_info("__get_metapage: inode = 0x%p, lblock = 0x%lx", inode, lblock);
-
+ jfs_info("__get_metapage: ino = %ld, lblock = 0x%lx, abs=%d",
+ inode->i_ino, lblock, absolute);
+
+ l2bsize = inode->i_blkbits;
+ l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
+ page_index = lblock >> l2BlocksPerPage;
+ page_offset = (lblock - (page_index << l2BlocksPerPage)) << l2bsize;
+ if ((page_offset + size) > PAGE_CACHE_SIZE) {
+ jfs_err("MetaData crosses page boundary!!");
+ jfs_err("lblock = %lx, size = %d", lblock, size);
+ dump_stack();
+ return NULL;
+ }
if (absolute)
- mapping = inode->i_sb->s_bdev->bd_inode->i_mapping;
+ mapping = JFS_SBI(inode->i_sb)->direct_inode->i_mapping;
else {
/*
* If an nfs client tries to read an inode that is larger
@@ -237,312 +631,212 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
mapping = inode->i_mapping;
}
- hash_ptr = meta_hash(mapping, lblock);
-again:
- spin_lock(&meta_lock);
- mp = search_hash(hash_ptr, mapping, lblock);
+ if (new && (PSIZE == PAGE_CACHE_SIZE)) {
+ page = grab_cache_page(mapping, page_index);
+ if (!page) {
+ jfs_err("grab_cache_page failed!");
+ return NULL;
+ }
+ SetPageUptodate(page);
+ } else {
+ page = read_cache_page(mapping, page_index,
+ (filler_t *)mapping->a_ops->readpage, NULL);
+ if (IS_ERR(page)) {
+ jfs_err("read_cache_page failed!");
+ return NULL;
+ }
+ lock_page(page);
+ }
+
+ mp = page_to_mp(page, page_offset);
if (mp) {
- page_found:
- if (test_bit(META_stale, &mp->flag)) {
- spin_unlock(&meta_lock);
- msleep(1);
- goto again;
+ if (mp->logical_size != size) {
+ jfs_error(inode->i_sb,
+ "__get_metapage: mp->logical_size != size");
+ jfs_err("logical_size = %d, size = %d",
+ mp->logical_size, size);
+ dump_stack();
+ goto unlock;
}
mp->count++;
lock_metapage(mp);
- spin_unlock(&meta_lock);
if (test_bit(META_discard, &mp->flag)) {
if (!new) {
jfs_error(inode->i_sb,
"__get_metapage: using a "
"discarded metapage");
- release_metapage(mp);
- return NULL;
+ discard_metapage(mp);
+ goto unlock;
}
clear_bit(META_discard, &mp->flag);
}
- jfs_info("__get_metapage: found 0x%p, in hash", mp);
- if (mp->logical_size != size) {
- jfs_error(inode->i_sb,
- "__get_metapage: mp->logical_size != size");
- release_metapage(mp);
- return NULL;
- }
} else {
- l2bsize = inode->i_blkbits;
- l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
- page_index = lblock >> l2BlocksPerPage;
- page_offset = (lblock - (page_index << l2BlocksPerPage)) <<
- l2bsize;
- if ((page_offset + size) > PAGE_CACHE_SIZE) {
- spin_unlock(&meta_lock);
- jfs_err("MetaData crosses page boundary!!");
- return NULL;
- }
-
- /*
- * Locks held on aggregate inode pages are usually
- * not held long, and they are taken in critical code
- * paths (committing dirty inodes, txCommit thread)
- *
- * Attempt to get metapage without blocking, tapping into
- * reserves if necessary.
- */
- mp = NULL;
- if (JFS_IP(inode)->fileset == AGGREGATE_I) {
- mp = alloc_metapage(GFP_ATOMIC);
- if (!mp) {
- /*
- * mempool is supposed to protect us from
- * failing here. We will try a blocking
- * call, but a deadlock is possible here
- */
- printk(KERN_WARNING
- "__get_metapage: atomic call to mempool_alloc failed.\n");
- printk(KERN_WARNING
- "Will attempt blocking call\n");
- }
- }
- if (!mp) {
- struct metapage *mp2;
-
- spin_unlock(&meta_lock);
- mp = alloc_metapage(GFP_NOFS);
- spin_lock(&meta_lock);
-
- /* we dropped the meta_lock, we need to search the
- * hash again.
- */
- mp2 = search_hash(hash_ptr, mapping, lblock);
- if (mp2) {
- free_metapage(mp);
- mp = mp2;
- goto page_found;
- }
- }
+ INCREMENT(mpStat.pagealloc);
+ mp = alloc_metapage(GFP_NOFS);
+ mp->page = page;
mp->flag = 0;
- lock_metapage(mp);
- if (absolute)
- set_bit(META_absolute, &mp->flag);
mp->xflag = COMMIT_PAGE;
mp->count = 1;
- atomic_set(&mp->nohomeok,0);
- mp->mapping = mapping;
- mp->index = lblock;
- mp->page = NULL;
+ mp->nohomeok = 0;
mp->logical_size = size;
- add_to_hash(mp, hash_ptr);
- spin_unlock(&meta_lock);
-
- if (new) {
- jfs_info("__get_metapage: Calling grab_cache_page");
- mp->page = grab_cache_page(mapping, page_index);
- if (!mp->page) {
- jfs_err("grab_cache_page failed!");
- goto freeit;
- } else {
- INCREMENT(mpStat.pagealloc);
- unlock_page(mp->page);
- }
- } else {
- jfs_info("__get_metapage: Calling read_cache_page");
- mp->page = read_cache_page(mapping, lblock,
- (filler_t *)mapping->a_ops->readpage, NULL);
- if (IS_ERR(mp->page)) {
- jfs_err("read_cache_page failed!");
- goto freeit;
- } else
- INCREMENT(mpStat.pagealloc);
+ mp->data = page_address(page) + page_offset;
+ mp->index = lblock;
+ if (unlikely(insert_metapage(page, mp))) {
+ free_metapage(mp);
+ goto unlock;
}
- mp->data = kmap(mp->page) + page_offset;
+ lock_metapage(mp);
}
- if (new)
+ if (new) {
+ jfs_info("zeroing mp = 0x%p", mp);
memset(mp->data, 0, PSIZE);
+ }
- jfs_info("__get_metapage: returning = 0x%p", mp);
+ unlock_page(page);
+ jfs_info("__get_metapage: returning = 0x%p data = 0x%p", mp, mp->data);
return mp;
-freeit:
- spin_lock(&meta_lock);
- remove_from_hash(mp, hash_ptr);
- free_metapage(mp);
- spin_unlock(&meta_lock);
+unlock:
+ unlock_page(page);
return NULL;
}
-void hold_metapage(struct metapage * mp, int force)
+void grab_metapage(struct metapage * mp)
{
- spin_lock(&meta_lock);
-
+ jfs_info("grab_metapage: mp = 0x%p", mp);
+ page_cache_get(mp->page);
+ lock_page(mp->page);
mp->count++;
-
- if (force) {
- ASSERT (!(test_bit(META_forced, &mp->flag)));
- if (trylock_metapage(mp))
- set_bit(META_forced, &mp->flag);
- } else
- lock_metapage(mp);
-
- spin_unlock(&meta_lock);
+ lock_metapage(mp);
+ unlock_page(mp->page);
}
-static void __write_metapage(struct metapage * mp)
+void force_metapage(struct metapage *mp)
{
- int l2bsize = mp->mapping->host->i_blkbits;
- int l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
- unsigned long page_index;
- unsigned long page_offset;
- int rc;
-
- jfs_info("__write_metapage: mp = 0x%p", mp);
-
- page_index = mp->page->index;
- page_offset =
- (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
+ struct page *page = mp->page;
+ jfs_info("force_metapage: mp = 0x%p", mp);
+ set_bit(META_forcewrite, &mp->flag);
+ clear_bit(META_sync, &mp->flag);
+ page_cache_get(page);
+ lock_page(page);
+ set_page_dirty(page);
+ write_one_page(page, 1);
+ clear_bit(META_forcewrite, &mp->flag);
+ page_cache_release(page);
+}
+extern void hold_metapage(struct metapage *mp)
+{
lock_page(mp->page);
- rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
- page_offset +
- mp->logical_size);
- if (rc) {
- jfs_err("prepare_write return %d!", rc);
- ClearPageUptodate(mp->page);
+}
+
+extern void put_metapage(struct metapage *mp)
+{
+ if (mp->count || mp->nohomeok) {
+ /* Someone else will release this */
unlock_page(mp->page);
- clear_bit(META_dirty, &mp->flag);
return;
}
- rc = mp->mapping->a_ops->commit_write(NULL, mp->page, page_offset,
- page_offset +
- mp->logical_size);
- if (rc) {
- jfs_err("commit_write returned %d", rc);
- }
-
+ page_cache_get(mp->page);
+ mp->count++;
+ lock_metapage(mp);
unlock_page(mp->page);
- clear_bit(META_dirty, &mp->flag);
-
- jfs_info("__write_metapage done");
-}
-
-static inline void sync_metapage(struct metapage *mp)
-{
- struct page *page = mp->page;
-
- page_cache_get(page);
- lock_page(page);
-
- /* we're done with this page - no need to check for errors */
- if (page_has_buffers(page))
- write_one_page(page, 1);
- else
- unlock_page(page);
- page_cache_release(page);
+ release_metapage(mp);
}
void release_metapage(struct metapage * mp)
{
- struct jfs_log *log;
-
+ struct page *page = mp->page;
jfs_info("release_metapage: mp = 0x%p, flag = 0x%lx", mp, mp->flag);
- spin_lock(&meta_lock);
- if (test_bit(META_forced, &mp->flag)) {
- clear_bit(META_forced, &mp->flag);
- mp->count--;
- spin_unlock(&meta_lock);
- return;
- }
+ BUG_ON(!page);
+
+ lock_page(page);
+ unlock_metapage(mp);
assert(mp->count);
- if (--mp->count || atomic_read(&mp->nohomeok)) {
- unlock_metapage(mp);
- spin_unlock(&meta_lock);
+ if (--mp->count || mp->nohomeok) {
+ unlock_page(page);
+ page_cache_release(page);
return;
}
- if (mp->page) {
- set_bit(META_stale, &mp->flag);
- spin_unlock(&meta_lock);
- kunmap(mp->page);
- mp->data = NULL;
- if (test_bit(META_dirty, &mp->flag))
- __write_metapage(mp);
+ if (test_bit(META_dirty, &mp->flag)) {
+ set_page_dirty(page);
if (test_bit(META_sync, &mp->flag)) {
- sync_metapage(mp);
clear_bit(META_sync, &mp->flag);
+ write_one_page(page, 1);
+ lock_page(page); /* write_one_page unlocks the page */
}
+ } else if (mp->lsn) /* discard_metapage doesn't remove it */
+ remove_from_logsync(mp);
- if (test_bit(META_discard, &mp->flag)) {
- lock_page(mp->page);
- block_invalidatepage(mp->page, 0);
- unlock_page(mp->page);
- }
-
- page_cache_release(mp->page);
- mp->page = NULL;
- INCREMENT(mpStat.pagefree);
- spin_lock(&meta_lock);
- }
+#if MPS_PER_PAGE == 1
+ /*
+ * If we know this is the only thing in the page, we can throw
+ * the page out of the page cache. If pages are larger, we
+ * don't want to do this.
+ */
- if (mp->lsn) {
- /*
- * Remove metapage from logsynclist.
- */
- log = mp->log;
- LOGSYNC_LOCK(log);
- mp->log = NULL;
- mp->lsn = 0;
- mp->clsn = 0;
- log->count--;
- list_del(&mp->synclist);
- LOGSYNC_UNLOCK(log);
+ /* Retest mp->count since we may have released page lock */
+ if (test_bit(META_discard, &mp->flag) && !mp->count) {
+ clear_page_dirty(page);
+ ClearPageUptodate(page);
+#ifdef _NOT_YET
+ if (page->mapping) {
+ /* Remove from page cache and page cache reference */
+ remove_from_page_cache(page);
+ page_cache_release(page);
+ metapage_releasepage(page, 0);
+ }
+#endif
}
- remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
- spin_unlock(&meta_lock);
-
- free_metapage(mp);
+#else
+ /* Try to keep metapages from using up too much memory */
+ drop_metapage(page, mp);
+#endif
+ unlock_page(page);
+ page_cache_release(page);
}
void __invalidate_metapages(struct inode *ip, s64 addr, int len)
{
- struct metapage **hash_ptr;
- unsigned long lblock;
+ sector_t lblock;
int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits;
+ int BlocksPerPage = 1 << l2BlocksPerPage;
/* All callers are interested in block device's mapping */
- struct address_space *mapping = ip->i_sb->s_bdev->bd_inode->i_mapping;
+ struct address_space *mapping =
+ JFS_SBI(ip->i_sb)->direct_inode->i_mapping;
struct metapage *mp;
struct page *page;
+ unsigned int offset;
/*
- * First, mark metapages to discard. They will eventually be
+ * Mark metapages to discard. They will eventually be
* released, but should not be written.
*/
- for (lblock = addr; lblock < addr + len;
- lblock += 1 << l2BlocksPerPage) {
- hash_ptr = meta_hash(mapping, lblock);
-again:
- spin_lock(&meta_lock);
- mp = search_hash(hash_ptr, mapping, lblock);
- if (mp) {
- if (test_bit(META_stale, &mp->flag)) {
- spin_unlock(&meta_lock);
- msleep(1);
- goto again;
- }
+ for (lblock = addr & ~(BlocksPerPage - 1); lblock < addr + len;
+ lblock += BlocksPerPage) {
+ page = find_lock_page(mapping, lblock >> l2BlocksPerPage);
+ if (!page)
+ continue;
+ for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) {
+ mp = page_to_mp(page, offset);
+ if (!mp)
+ continue;
+ if (mp->index < addr)
+ continue;
+ if (mp->index >= addr + len)
+ break;
clear_bit(META_dirty, &mp->flag);
set_bit(META_discard, &mp->flag);
- spin_unlock(&meta_lock);
- } else {
- spin_unlock(&meta_lock);
- page = find_lock_page(mapping, lblock>>l2BlocksPerPage);
- if (page) {
- block_invalidatepage(page, 0);
- unlock_page(page);
- page_cache_release(page);
- }
+ if (mp->lsn)
+ remove_from_logsync(mp);
}
+ unlock_page(page);
+ page_cache_release(page);
}
}
diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
index 0e58aba58c37..991e9fb84c75 100644
--- a/fs/jfs/jfs_metapage.h
+++ b/fs/jfs/jfs_metapage.h
@@ -33,38 +33,27 @@ struct metapage {
unsigned long flag; /* See Below */
unsigned long count; /* Reference count */
void *data; /* Data pointer */
-
- /* list management stuff */
- struct metapage *hash_prev;
- struct metapage *hash_next; /* Also used for free list */
-
- /*
- * mapping & index become redundant, but we need these here to
- * add the metapage to the hash before we have the real page
- */
- struct address_space *mapping;
- unsigned long index;
+ sector_t index; /* block address of page */
wait_queue_head_t wait;
/* implementation */
struct page *page;
- unsigned long logical_size;
+ unsigned int logical_size;
/* Journal management */
int clsn;
- atomic_t nohomeok;
+ int nohomeok;
struct jfs_log *log;
};
/* metapage flag */
#define META_locked 0
-#define META_absolute 1
-#define META_free 2
-#define META_dirty 3
-#define META_sync 4
-#define META_discard 5
-#define META_forced 6
-#define META_stale 7
+#define META_free 1
+#define META_dirty 2
+#define META_sync 3
+#define META_discard 4
+#define META_forcewrite 5
+#define META_io 6
#define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
@@ -80,7 +69,16 @@ extern struct metapage *__get_metapage(struct inode *inode,
__get_metapage(inode, lblock, size, absolute, TRUE)
extern void release_metapage(struct metapage *);
-extern void hold_metapage(struct metapage *, int);
+extern void grab_metapage(struct metapage *);
+extern void force_metapage(struct metapage *);
+
+/*
+ * hold_metapage and put_metapage are used in conjuction. The page lock
+ * is not dropped between the two, so no other threads can get or release
+ * the metapage
+ */
+extern void hold_metapage(struct metapage *);
+extern void put_metapage(struct metapage *);
static inline void write_metapage(struct metapage *mp)
{
@@ -101,6 +99,46 @@ static inline void discard_metapage(struct metapage *mp)
release_metapage(mp);
}
+static inline void metapage_nohomeok(struct metapage *mp)
+{
+ struct page *page = mp->page;
+ lock_page(page);
+ if (!mp->nohomeok++) {
+ mark_metapage_dirty(mp);
+ page_cache_get(page);
+ wait_on_page_writeback(page);
+ }
+ unlock_page(page);
+}
+
+/*
+ * This serializes access to mp->lsn when metapages are added to logsynclist
+ * without setting nohomeok. i.e. updating imap & dmap
+ */
+static inline void metapage_wait_for_io(struct metapage *mp)
+{
+ if (test_bit(META_io, &mp->flag))
+ wait_on_page_writeback(mp->page);
+}
+
+/*
+ * This is called when already holding the metapage
+ */
+static inline void _metapage_homeok(struct metapage *mp)
+{
+ if (!--mp->nohomeok)
+ page_cache_release(mp->page);
+}
+
+static inline void metapage_homeok(struct metapage *mp)
+{
+ hold_metapage(mp);
+ _metapage_homeok(mp);
+ put_metapage(mp);
+}
+
+extern struct address_space_operations jfs_metapage_aops;
+
/*
* This routines invalidate all pages for an extent.
*/
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index c535ffd638e8..032d111bc330 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -285,11 +285,6 @@ int jfs_mount_rw(struct super_block *sb, int remount)
*/
logMOUNT(sb);
- /*
- * Set page cache allocation policy
- */
- mapping_set_gfp_mask(sb->s_bdev->bd_inode->i_mapping, GFP_NOFS);
-
return rc;
}
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index f40301d93f74..e93d01aa12c4 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -227,6 +227,7 @@ static lid_t txLockAlloc(void)
static void txLockFree(lid_t lid)
{
+ TxLock[lid].tid = 0;
TxLock[lid].next = TxAnchor.freelock;
TxAnchor.freelock = lid;
TxAnchor.tlocksInUse--;
@@ -566,9 +567,6 @@ void txEnd(tid_t tid)
* synchronize with logsync barrier
*/
if (test_bit(log_SYNCBARRIER, &log->flag)) {
- /* forward log syncpt */
- /* lmSync(log); */
-
jfs_info("log barrier off: 0x%x", log->lsn);
/* enable new transactions start */
@@ -576,15 +574,22 @@ void txEnd(tid_t tid)
/* wakeup all waitors for logsync barrier */
TXN_WAKEUP(&log->syncwait);
+
+ TXN_UNLOCK();
+
+ /* forward log syncpt */
+ jfs_syncpt(log);
+
+ goto wakeup;
}
}
+ TXN_UNLOCK();
+wakeup:
/*
* wakeup all waitors for a free tblock
*/
TXN_WAKEUP(&TxAnchor.freewait);
-
- TXN_UNLOCK();
}
@@ -633,8 +638,10 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
/* is page locked by the requester transaction ? */
tlck = lid_to_tlock(lid);
- if ((xtid = tlck->tid) == tid)
+ if ((xtid = tlck->tid) == tid) {
+ TXN_UNLOCK();
goto grantLock;
+ }
/*
* is page locked by anonymous transaction/lock ?
@@ -649,6 +656,7 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
*/
if (xtid == 0) {
tlck->tid = tid;
+ TXN_UNLOCK();
tblk = tid_to_tblock(tid);
/*
* The order of the tlocks in the transaction is important
@@ -706,17 +714,18 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
*/
tlck->tid = tid;
+ TXN_UNLOCK();
+
/* mark tlock for meta-data page */
if (mp->xflag & COMMIT_PAGE) {
tlck->flag = tlckPAGELOCK;
/* mark the page dirty and nohomeok */
- mark_metapage_dirty(mp);
- atomic_inc(&mp->nohomeok);
+ metapage_nohomeok(mp);
jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
- mp, atomic_read(&mp->nohomeok), tid, tlck);
+ mp, mp->nohomeok, tid, tlck);
/* if anonymous transaction, and buffer is on the group
* commit synclist, mark inode to show this. This will
@@ -762,8 +771,10 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
if (tlck->next == 0) {
/* This inode's first anonymous transaction */
jfs_ip->atltail = lid;
+ TXN_LOCK();
list_add_tail(&jfs_ip->anon_inode_list,
&TxAnchor.anon_list);
+ TXN_UNLOCK();
}
}
@@ -821,8 +832,6 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
grantLock:
tlck->type |= type;
- TXN_UNLOCK();
-
return tlck;
/*
@@ -841,11 +850,19 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
BUG();
}
INCREMENT(stattx.waitlock); /* statistics */
+ TXN_UNLOCK();
release_metapage(mp);
+ TXN_LOCK();
+ xtid = tlck->tid; /* reaquire after dropping TXN_LOCK */
jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
tid, xtid, lid);
- TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+
+ /* Recheck everything since dropping TXN_LOCK */
+ if (xtid && (tlck->mp == mp) && (mp->lid == lid))
+ TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+ else
+ TXN_UNLOCK();
jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid);
return NULL;
@@ -906,6 +923,7 @@ static void txUnlock(struct tblock * tblk)
struct metapage *mp;
struct jfs_log *log;
int difft, diffp;
+ unsigned long flags;
jfs_info("txUnlock: tblk = 0x%p", tblk);
log = JFS_SBI(tblk->sb)->log;
@@ -925,19 +943,14 @@ static void txUnlock(struct tblock * tblk)
assert(mp->xflag & COMMIT_PAGE);
/* hold buffer
- *
- * It's possible that someone else has the metapage.
- * The only things were changing are nohomeok, which
- * is handled atomically, and clsn which is protected
- * by the LOGSYNC_LOCK.
*/
- hold_metapage(mp, 1);
+ hold_metapage(mp);
- assert(atomic_read(&mp->nohomeok) > 0);
- atomic_dec(&mp->nohomeok);
+ assert(mp->nohomeok > 0);
+ _metapage_homeok(mp);
/* inherit younger/larger clsn */
- LOGSYNC_LOCK(log);
+ LOGSYNC_LOCK(log, flags);
if (mp->clsn) {
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log);
@@ -945,16 +958,11 @@ static void txUnlock(struct tblock * tblk)
mp->clsn = tblk->clsn;
} else
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
assert(!(tlck->flag & tlckFREEPAGE));
- if (tlck->flag & tlckWRITEPAGE) {
- write_metapage(mp);
- } else {
- /* release page which has been forced */
- release_metapage(mp);
- }
+ put_metapage(mp);
}
/* insert tlock, and linelock(s) of the tlock if any,
@@ -981,10 +989,10 @@ static void txUnlock(struct tblock * tblk)
* has been inserted in logsync list at txUpdateMap())
*/
if (tblk->lsn) {
- LOGSYNC_LOCK(log);
+ LOGSYNC_LOCK(log, flags);
log->count--;
list_del(&tblk->synclist);
- LOGSYNC_UNLOCK(log);
+ LOGSYNC_UNLOCK(log, flags);
}
}
@@ -1573,8 +1581,8 @@ static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* the last entry, so don't bother logging this
*/
mp->lid = 0;
- hold_metapage(mp, 0);
- atomic_dec(&mp->nohomeok);
+ grab_metapage(mp);
+ metapage_homeok(mp);
discard_metapage(mp);
tlck->mp = NULL;
return 0;
@@ -1712,7 +1720,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
struct maplock *maplock;
struct xdlistlock *xadlock;
struct pxd_lock *pxdlock;
- pxd_t *pxd;
+ pxd_t *page_pxd;
int next, lwm, hwm;
ip = tlck->ip;
@@ -1722,7 +1730,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
lrd->log.redopage.type = cpu_to_le16(LOG_XTREE);
lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE);
- pxd = &lrd->log.redopage.pxd;
+ page_pxd = &lrd->log.redopage.pxd;
if (tlck->type & tlckBTROOT) {
lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
@@ -1752,9 +1760,9 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* applying the after-image to the meta-data page.
*/
lrd->type = cpu_to_le16(LOG_REDOPAGE);
-// *pxd = mp->cm_pxd;
- PXDaddress(pxd, mp->index);
- PXDlength(pxd,
+// *page_pxd = mp->cm_pxd;
+ PXDaddress(page_pxd, mp->index);
+ PXDlength(page_pxd,
mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
@@ -1776,25 +1784,31 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
tlck->flag |= tlckUPDATEMAP;
xadlock->flag = mlckALLOCXADLIST;
xadlock->count = next - lwm;
- if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+ if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
int i;
+ pxd_t *pxd;
/*
* Lazy commit may allow xtree to be modified before
* txUpdateMap runs. Copy xad into linelock to
* preserve correct data.
+ *
+ * We can fit twice as may pxd's as xads in the lock
*/
- xadlock->xdlist = &xtlck->pxdlock;
- memcpy(xadlock->xdlist, &p->xad[lwm],
- sizeof(xad_t) * xadlock->count);
-
- for (i = 0; i < xadlock->count; i++)
+ xadlock->flag = mlckALLOCPXDLIST;
+ pxd = xadlock->xdlist = &xtlck->pxdlock;
+ for (i = 0; i < xadlock->count; i++) {
+ PXDaddress(pxd, addressXAD(&p->xad[lwm + i]));
+ PXDlength(pxd, lengthXAD(&p->xad[lwm + i]));
p->xad[lwm + i].flag &=
~(XAD_NEW | XAD_EXTENDED);
+ pxd++;
+ }
} else {
/*
* xdlist will point to into inode's xtree, ensure
* that transaction is not committed lazily.
*/
+ xadlock->flag = mlckALLOCXADLIST;
xadlock->xdlist = &p->xad[lwm];
tblk->xflag &= ~COMMIT_LAZY;
}
@@ -1836,8 +1850,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
if (tblk->xflag & COMMIT_TRUNCATE) {
/* write NOREDOPAGE for the page */
lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
- PXDaddress(pxd, mp->index);
- PXDlength(pxd,
+ PXDaddress(page_pxd, mp->index);
+ PXDlength(page_pxd,
mp->logical_size >> tblk->sb->
s_blocksize_bits);
lrd->backchain =
@@ -1872,22 +1886,32 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* deleted page itself;
*/
tlck->flag |= tlckUPDATEMAP;
- xadlock->flag = mlckFREEXADLIST;
xadlock->count = hwm - XTENTRYSTART + 1;
- if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+ if ((xadlock->count <= 4) && (tblk->xflag & COMMIT_LAZY)) {
+ int i;
+ pxd_t *pxd;
/*
* Lazy commit may allow xtree to be modified before
* txUpdateMap runs. Copy xad into linelock to
* preserve correct data.
+ *
+ * We can fit twice as may pxd's as xads in the lock
*/
- xadlock->xdlist = &xtlck->pxdlock;
- memcpy(xadlock->xdlist, &p->xad[XTENTRYSTART],
- sizeof(xad_t) * xadlock->count);
+ xadlock->flag = mlckFREEPXDLIST;
+ pxd = xadlock->xdlist = &xtlck->pxdlock;
+ for (i = 0; i < xadlock->count; i++) {
+ PXDaddress(pxd,
+ addressXAD(&p->xad[XTENTRYSTART + i]));
+ PXDlength(pxd,
+ lengthXAD(&p->xad[XTENTRYSTART + i]));
+ pxd++;
+ }
} else {
/*
* xdlist will point to into inode's xtree, ensure
* that transaction is not committed lazily.
*/
+ xadlock->flag = mlckFREEXADLIST;
xadlock->xdlist = &p->xad[XTENTRYSTART];
tblk->xflag &= ~COMMIT_LAZY;
}
@@ -1918,7 +1942,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* header ?
*/
if (tlck->type & tlckTRUNCATE) {
- pxd_t tpxd; /* truncated extent of xad */
+ pxd_t pxd; /* truncated extent of xad */
int twm;
/*
@@ -1947,8 +1971,9 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* applying the after-image to the meta-data page.
*/
lrd->type = cpu_to_le16(LOG_REDOPAGE);
- PXDaddress(pxd, mp->index);
- PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
+ PXDaddress(page_pxd, mp->index);
+ PXDlength(page_pxd,
+ mp->logical_size >> tblk->sb->s_blocksize_bits);
lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
/*
@@ -1966,7 +1991,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
lrd->log.updatemap.nxd = cpu_to_le16(1);
lrd->log.updatemap.pxd = pxdlock->pxd;
- tpxd = pxdlock->pxd; /* save to format maplock */
+ pxd = pxdlock->pxd; /* save to format maplock */
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, NULL));
}
@@ -2035,7 +2060,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
pxdlock = (struct pxd_lock *) xadlock;
pxdlock->flag = mlckFREEPXD;
pxdlock->count = 1;
- pxdlock->pxd = tpxd;
+ pxdlock->pxd = pxd;
jfs_info("xtLog: truncate ip:0x%p mp:0x%p count:%d "
"hwm:%d", ip, mp, pxdlock->count, hwm);
@@ -2253,7 +2278,8 @@ void txForce(struct tblock * tblk)
tlck->flag &= ~tlckWRITEPAGE;
/* do not release page to freelist */
-
+ force_metapage(mp);
+#if 0
/*
* The "right" thing to do here is to
* synchronously write the metadata.
@@ -2265,9 +2291,10 @@ void txForce(struct tblock * tblk)
* we can get by with synchronously writing
* the pages when they are released.
*/
- assert(atomic_read(&mp->nohomeok));
+ assert(mp->nohomeok);
set_bit(META_dirty, &mp->flag);
set_bit(META_sync, &mp->flag);
+#endif
}
}
}
@@ -2327,7 +2354,7 @@ static void txUpdateMap(struct tblock * tblk)
*/
mp = tlck->mp;
ASSERT(mp->xflag & COMMIT_PAGE);
- hold_metapage(mp, 0);
+ grab_metapage(mp);
}
/*
@@ -2377,8 +2404,8 @@ static void txUpdateMap(struct tblock * tblk)
ASSERT(mp->lid == lid);
tlck->mp->lid = 0;
}
- assert(atomic_read(&mp->nohomeok) == 1);
- atomic_dec(&mp->nohomeok);
+ assert(mp->nohomeok == 1);
+ metapage_homeok(mp);
discard_metapage(mp);
tlck->mp = NULL;
}
@@ -2844,24 +2871,9 @@ static void LogSyncRelease(struct metapage * mp)
{
struct jfs_log *log = mp->log;
- assert(atomic_read(&mp->nohomeok));
+ assert(mp->nohomeok);
assert(log);
- atomic_dec(&mp->nohomeok);
-
- if (atomic_read(&mp->nohomeok))
- return;
-
- hold_metapage(mp, 0);
-
- LOGSYNC_LOCK(log);
- mp->log = NULL;
- mp->lsn = 0;
- mp->clsn = 0;
- log->count--;
- list_del_init(&mp->synclist);
- LOGSYNC_UNLOCK(log);
-
- release_metapage(mp);
+ metapage_homeok(mp);
}
/*
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index f31a9e3f3fec..5cf91785b541 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -49,7 +49,6 @@
*/
int jfs_umount(struct super_block *sb)
{
- struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct inode *ipbmap = sbi->ipbmap;
struct inode *ipimap = sbi->ipimap;
@@ -109,8 +108,8 @@ int jfs_umount(struct super_block *sb)
* Make sure all metadata makes it to disk before we mark
* the superblock as clean
*/
- filemap_fdatawrite(bdev_mapping);
- filemap_fdatawait(bdev_mapping);
+ filemap_fdatawrite(sbi->direct_inode->i_mapping);
+ filemap_fdatawait(sbi->direct_inode->i_mapping);
/*
* ensure all file system file pages are propagated to their
@@ -123,9 +122,6 @@ int jfs_umount(struct super_block *sb)
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
- /* Restore default gfp_mask for bdev */
- mapping_set_gfp_mask(bdev_mapping, GFP_USER);
-
/*
* close log:
*
@@ -140,7 +136,6 @@ int jfs_umount(struct super_block *sb)
int jfs_umount_rw(struct super_block *sb)
{
- struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
@@ -166,13 +161,10 @@ int jfs_umount_rw(struct super_block *sb)
* mark the superblock clean before everything is flushed to
* disk.
*/
- filemap_fdatawrite(bdev_mapping);
- filemap_fdatawait(bdev_mapping);
+ filemap_fdatawrite(sbi->direct_inode->i_mapping);
+ filemap_fdatawait(sbi->direct_inode->i_mapping);
updateSuper(sb, FM_CLEAN);
- /* Restore default gfp_mask for bdev */
- mapping_set_gfp_mask(bdev_mapping, GFP_USER);
-
return lmLogClose(sb);
}
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index 11c58c54b818..2c1f311914a1 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -111,8 +111,8 @@ static struct {
/*
* forward references
*/
-static int xtSearch(struct inode *ip,
- s64 xoff, int *cmpp, struct btstack * btstack, int flag);
+static int xtSearch(struct inode *ip, s64 xoff, s64 *next, int *cmpp,
+ struct btstack * btstack, int flag);
static int xtSplitUp(tid_t tid,
struct inode *ip,
@@ -159,11 +159,12 @@ int xtLookup(struct inode *ip, s64 lstart,
xtpage_t *p;
int index;
xad_t *xad;
- s64 size, xoff, xend;
+ s64 next, size, xoff, xend;
int xlen;
s64 xaddr;
- *plen = 0;
+ *paddr = 0;
+ *plen = llen;
if (!no_check) {
/* is lookup offset beyond eof ? */
@@ -180,7 +181,7 @@ int xtLookup(struct inode *ip, s64 lstart,
* search for the xad entry covering the logical extent
*/
//search:
- if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) {
+ if ((rc = xtSearch(ip, lstart, &next, &cmp, &btstack, 0))) {
jfs_err("xtLookup: xtSearch returned %d", rc);
return rc;
}
@@ -198,8 +199,11 @@ int xtLookup(struct inode *ip, s64 lstart,
* lstart is a page start address,
* i.e., lstart cannot start in a hole;
*/
- if (cmp)
+ if (cmp) {
+ if (next)
+ *plen = min(next - lstart, llen);
goto out;
+ }
/*
* lxd covered by xad
@@ -284,7 +288,7 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
if (lstart >= size)
return 0;
- if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0)))
+ if ((rc = xtSearch(ip, lstart, NULL, &cmp, &btstack, 0)))
return rc;
/*
@@ -488,6 +492,7 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
* parameters:
* ip - file object;
* xoff - extent offset;
+ * nextp - address of next extent (if any) for search miss
* cmpp - comparison result:
* btstack - traverse stack;
* flag - search process flag (XT_INSERT);
@@ -497,7 +502,7 @@ int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
* *cmpp is set to result of comparison with the entry returned.
* the page containing the entry is pinned at exit.
*/
-static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
+static int xtSearch(struct inode *ip, s64 xoff, s64 *nextp,
int *cmpp, struct btstack * btstack, int flag)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
@@ -511,6 +516,7 @@ static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
struct btframe *btsp;
int nsplit = 0; /* number of pages to split */
s64 t64;
+ s64 next = 0;
INCREMENT(xtStat.search);
@@ -579,6 +585,7 @@ static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
* previous and this entry
*/
*cmpp = 1;
+ next = t64;
goto out;
}
@@ -623,6 +630,9 @@ static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
/* update sequential access heuristics */
jfs_ip->btindex = index;
+ if (nextp)
+ *nextp = next;
+
INCREMENT(xtStat.fastSearch);
return 0;
}
@@ -675,10 +685,11 @@ static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
return 0;
}
-
/* search hit - internal page:
* descend/search its child page
*/
+ if (index < p->header.nextindex - 1)
+ next = offsetXAD(&p->xad[index + 1]);
goto next;
}
@@ -694,6 +705,8 @@ static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
* base is the smallest index with key (Kj) greater than
* search key (K) and may be zero or maxentry index.
*/
+ if (base < p->header.nextindex)
+ next = offsetXAD(&p->xad[base]);
/*
* search miss - leaf page:
*
@@ -727,6 +740,9 @@ static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */
jfs_ip->btorder = BT_RANDOM;
jfs_ip->btindex = base;
+ if (nextp)
+ *nextp = next;
+
return 0;
}
@@ -793,6 +809,7 @@ int xtInsert(tid_t tid, /* transaction id */
struct xtsplit split; /* split information */
xad_t *xad;
int cmp;
+ s64 next;
struct tlock *tlck;
struct xtlock *xtlck;
@@ -806,7 +823,7 @@ int xtInsert(tid_t tid, /* transaction id */
* n.b. xtSearch() may return index of maxentry of
* the full page.
*/
- if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+ if ((rc = xtSearch(ip, xoff, &next, &cmp, &btstack, XT_INSERT)))
return rc;
/* retrieve search result */
@@ -814,7 +831,7 @@ int xtInsert(tid_t tid, /* transaction id */
/* This test must follow XT_GETSEARCH since mp must be valid if
* we branch to out: */
- if (cmp == 0) {
+ if ((cmp == 0) || (next && (xlen > next - xoff))) {
rc = -EEXIST;
goto out;
}
@@ -1626,7 +1643,7 @@ int xtExtend(tid_t tid, /* transaction id */
jfs_info("xtExtend: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
/* there must exist extent to be extended */
- if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
+ if ((rc = xtSearch(ip, xoff - 1, NULL, &cmp, &btstack, XT_INSERT)))
return rc;
/* retrieve search result */
@@ -1794,7 +1811,7 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
*/
/* there must exist extent to be tailgated */
- if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+ if ((rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, XT_INSERT)))
return rc;
/* retrieve search result */
@@ -1977,7 +1994,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
nxlen = lengthXAD(nxad);
nxaddr = addressXAD(nxad);
- if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+ if ((rc = xtSearch(ip, nxoff, NULL, &cmp, &btstack, XT_INSERT)))
return rc;
/* retrieve search result */
@@ -2291,7 +2308,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
if (nextindex == le16_to_cpu(p->header.maxentry)) {
XT_PUTPAGE(mp);
- if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+ if ((rc = xtSearch(ip, nxoff, NULL, &cmp, &btstack, XT_INSERT)))
return rc;
/* retrieve search result */
@@ -2438,6 +2455,7 @@ int xtAppend(tid_t tid, /* transaction id */
int nsplit, nblocks, xlen;
struct pxdlist pxdlist;
pxd_t *pxd;
+ s64 next;
xaddr = *xaddrp;
xlen = *xlenp;
@@ -2452,7 +2470,7 @@ int xtAppend(tid_t tid, /* transaction id */
* n.b. xtSearch() may return index of maxentry of
* the full page.
*/
- if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+ if ((rc = xtSearch(ip, xoff, &next, &cmp, &btstack, XT_INSERT)))
return rc;
/* retrieve search result */
@@ -2462,6 +2480,9 @@ int xtAppend(tid_t tid, /* transaction id */
rc = -EEXIST;
goto out;
}
+
+ if (next)
+ xlen = min(xlen, (int)(next - xoff));
//insert:
/*
* insert entry for new extent
@@ -2600,7 +2621,7 @@ int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag)
/*
* find the matching entry; xtSearch() pins the page
*/
- if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+ if ((rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0)))
return rc;
XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
@@ -2852,7 +2873,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */
*/
if (xtype == DATAEXT) {
/* search in leaf entry */
- rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+ rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0);
if (rc)
return rc;
@@ -2958,7 +2979,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */
}
/* get back parent page */
- if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+ if ((rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0)))
return rc;
XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
@@ -3991,7 +4012,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
if (committed_size) {
xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1;
- rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+ rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0);
if (rc)
return rc;
diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
index 2eb6869b6e72..c6dc254d3253 100644
--- a/fs/jfs/resize.c
+++ b/fs/jfs/resize.c
@@ -209,6 +209,9 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
*/
txQuiesce(sb);
+ /* Reset size of direct inode */
+ sbi->direct_inode->i_size = sb->s_bdev->bd_inode->i_size;
+
if (sbi->mntflag & JFS_INLINELOG) {
/*
* deactivate old inline log
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 5856866e24fc..5e774ed7fb64 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -210,6 +210,10 @@ static void jfs_put_super(struct super_block *sb)
unload_nls(sbi->nls_tab);
sbi->nls_tab = NULL;
+ truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
+ iput(sbi->direct_inode);
+ sbi->direct_inode = NULL;
+
kfree(sbi);
}
@@ -358,6 +362,12 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
}
if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+ /*
+ * Invalidate any previously read metadata. fsck may have
+ * changed the on-disk data since we mounted r/o
+ */
+ truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0);
+
JFS_SBI(sb)->flag = flag;
return jfs_mount_rw(sb, 1);
}
@@ -428,12 +438,26 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_op = &jfs_super_operations;
sb->s_export_op = &jfs_export_operations;
+ /*
+ * Initialize direct-mapping inode/address-space
+ */
+ inode = new_inode(sb);
+ if (inode == NULL)
+ goto out_kfree;
+ inode->i_ino = 0;
+ inode->i_nlink = 1;
+ inode->i_size = sb->s_bdev->bd_inode->i_size;
+ inode->i_mapping->a_ops = &jfs_metapage_aops;
+ mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+
+ sbi->direct_inode = inode;
+
rc = jfs_mount(sb);
if (rc) {
if (!silent) {
jfs_err("jfs_mount failed w/return code = %d", rc);
}
- goto out_kfree;
+ goto out_mount_failed;
}
if (sb->s_flags & MS_RDONLY)
sbi->log = NULL;
@@ -482,6 +506,13 @@ out_no_rw:
if (rc) {
jfs_err("jfs_umount failed with return code %d", rc);
}
+out_mount_failed:
+ filemap_fdatawrite(sbi->direct_inode->i_mapping);
+ filemap_fdatawait(sbi->direct_inode->i_mapping);
+ truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
+ make_bad_inode(sbi->direct_inode);
+ iput(sbi->direct_inode);
+ sbi->direct_inode = NULL;
out_kfree:
if (sbi->nls_tab)
unload_nls(sbi->nls_tab);
@@ -527,8 +558,10 @@ static int jfs_sync_fs(struct super_block *sb, int wait)
struct jfs_log *log = JFS_SBI(sb)->log;
/* log == NULL indicates read-only mount */
- if (log)
+ if (log) {
jfs_flush_journal(log, wait);
+ jfs_syncpt(log);
+ }
return 0;
}
diff --git a/fs/mpage.c b/fs/mpage.c
index e7d8d1a77606..32c7c8fcfce7 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -160,52 +160,6 @@ map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block)
} while (page_bh != head);
}
-/**
- * mpage_readpages - populate an address space with some pages, and
- * start reads against them.
- *
- * @mapping: the address_space
- * @pages: The address of a list_head which contains the target pages. These
- * pages have their ->index populated and are otherwise uninitialised.
- *
- * The page at @pages->prev has the lowest file offset, and reads should be
- * issued in @pages->prev to @pages->next order.
- *
- * @nr_pages: The number of pages at *@pages
- * @get_block: The filesystem's block mapper function.
- *
- * This function walks the pages and the blocks within each page, building and
- * emitting large BIOs.
- *
- * If anything unusual happens, such as:
- *
- * - encountering a page which has buffers
- * - encountering a page which has a non-hole after a hole
- * - encountering a page with non-contiguous blocks
- *
- * then this code just gives up and calls the buffer_head-based read function.
- * It does handle a page which has holes at the end - that is a common case:
- * the end-of-file on blocksize < PAGE_CACHE_SIZE setups.
- *
- * BH_Boundary explanation:
- *
- * There is a problem. The mpage read code assembles several pages, gets all
- * their disk mappings, and then submits them all. That's fine, but obtaining
- * the disk mappings may require I/O. Reads of indirect blocks, for example.
- *
- * So an mpage read of the first 16 blocks of an ext2 file will cause I/O to be
- * submitted in the following order:
- * 12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16
- * because the indirect block has to be read to get the mappings of blocks
- * 13,14,15,16. Obviously, this impacts performance.
- *
- * So what we do it to allow the filesystem's get_block() function to set
- * BH_Boundary when it maps block 11. BH_Boundary says: mapping of the block
- * after this one will require I/O against a block which is probably close to
- * this one. So you should push what I/O you have currently accumulated.
- *
- * This all causes the disk requests to be issued in the correct order.
- */
static struct bio *
do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
sector_t *last_block_in_bio, get_block_t get_block)
@@ -320,6 +274,52 @@ confused:
goto out;
}
+/**
+ * mpage_readpages - populate an address space with some pages, and
+ * start reads against them.
+ *
+ * @mapping: the address_space
+ * @pages: The address of a list_head which contains the target pages. These
+ * pages have their ->index populated and are otherwise uninitialised.
+ *
+ * The page at @pages->prev has the lowest file offset, and reads should be
+ * issued in @pages->prev to @pages->next order.
+ *
+ * @nr_pages: The number of pages at *@pages
+ * @get_block: The filesystem's block mapper function.
+ *
+ * This function walks the pages and the blocks within each page, building and
+ * emitting large BIOs.
+ *
+ * If anything unusual happens, such as:
+ *
+ * - encountering a page which has buffers
+ * - encountering a page which has a non-hole after a hole
+ * - encountering a page with non-contiguous blocks
+ *
+ * then this code just gives up and calls the buffer_head-based read function.
+ * It does handle a page which has holes at the end - that is a common case:
+ * the end-of-file on blocksize < PAGE_CACHE_SIZE setups.
+ *
+ * BH_Boundary explanation:
+ *
+ * There is a problem. The mpage read code assembles several pages, gets all
+ * their disk mappings, and then submits them all. That's fine, but obtaining
+ * the disk mappings may require I/O. Reads of indirect blocks, for example.
+ *
+ * So an mpage read of the first 16 blocks of an ext2 file will cause I/O to be
+ * submitted in the following order:
+ * 12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16
+ * because the indirect block has to be read to get the mappings of blocks
+ * 13,14,15,16. Obviously, this impacts performance.
+ *
+ * So what we do it to allow the filesystem's get_block() function to set
+ * BH_Boundary when it maps block 11. BH_Boundary says: mapping of the block
+ * after this one will require I/O against a block which is probably close to
+ * this one. So you should push what I/O you have currently accumulated.
+ *
+ * This all causes the disk requests to be issued in the correct order.
+ */
int
mpage_readpages(struct address_space *mapping, struct list_head *pages,
unsigned nr_pages, get_block_t get_block)
@@ -727,6 +727,8 @@ retry:
&last_block_in_bio, &ret, wbc,
writepage_fn);
}
+ if (unlikely(ret == WRITEPAGE_ACTIVATE))
+ unlock_page(page);
if (ret || (--(wbc->nr_to_write) <= 0))
done = 1;
if (wbc->nonblocking && bdi_write_congested(bdi)) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 39fd336cfdb9..07cafdf74ef2 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1419,6 +1419,8 @@ static struct file_operations proc_tgid_attr_operations;
static struct inode_operations proc_tgid_attr_inode_operations;
#endif
+static int get_tid_list(int index, unsigned int *tids, struct inode *dir);
+
/* SMP-safe */
static struct dentry *proc_pident_lookup(struct inode *dir,
struct dentry *dentry,
@@ -1458,7 +1460,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
*/
switch(p->type) {
case PROC_TGID_TASK:
- inode->i_nlink = 3;
+ inode->i_nlink = 2 + get_tid_list(2, NULL, dir);
inode->i_op = &proc_task_inode_operations;
inode->i_fop = &proc_task_operations;
break;
@@ -1701,13 +1703,13 @@ static struct inode_operations proc_self_inode_operations = {
};
/**
- * proc_pid_unhash - Unhash /proc/<pid> entry from the dcache.
+ * proc_pid_unhash - Unhash /proc/@pid entry from the dcache.
* @p: task that should be flushed.
*
- * Drops the /proc/<pid> dcache entry from the hash chains.
+ * Drops the /proc/@pid dcache entry from the hash chains.
*
- * Dropping /proc/<pid> entries and detach_pid must be synchroneous,
- * otherwise e.g. /proc/<pid>/exe might point to the wrong executable,
+ * Dropping /proc/@pid entries and detach_pid must be synchroneous,
+ * otherwise e.g. /proc/@pid/exe might point to the wrong executable,
* if the pid value is immediately reused. This is enforced by
* - caller must acquire spin_lock(p->proc_lock)
* - must be called before detach_pid()
@@ -1739,8 +1741,8 @@ struct dentry *proc_pid_unhash(struct task_struct *p)
}
/**
- * proc_pid_flush - recover memory used by stale /proc/<pid>/x entries
- * @proc_entry: directoy to prune.
+ * proc_pid_flush - recover memory used by stale /proc/@pid/x entries
+ * @proc_dentry: directoy to prune.
*
* Shrink the /proc directory that was used by the just killed thread.
*/
@@ -1800,8 +1802,12 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
inode->i_op = &proc_tgid_base_inode_operations;
inode->i_fop = &proc_tgid_base_operations;
- inode->i_nlink = 3;
inode->i_flags|=S_IMMUTABLE;
+#ifdef CONFIG_SECURITY
+ inode->i_nlink = 5;
+#else
+ inode->i_nlink = 4;
+#endif
dentry->d_op = &pid_base_dentry_operations;
@@ -1855,8 +1861,12 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
inode->i_op = &proc_tid_base_inode_operations;
inode->i_fop = &proc_tid_base_operations;
- inode->i_nlink = 3;
inode->i_flags|=S_IMMUTABLE;
+#ifdef CONFIG_SECURITY
+ inode->i_nlink = 4;
+#else
+ inode->i_nlink = 3;
+#endif
dentry->d_op = &pid_base_dentry_operations;
@@ -1935,7 +1945,8 @@ static int get_tid_list(int index, unsigned int *tids, struct inode *dir)
if (--index >= 0)
continue;
- tids[nr_tids] = tid;
+ if (tids != NULL)
+ tids[nr_tids] = tid;
nr_tids++;
if (nr_tids >= PROC_MAXPIDS)
break;
@@ -2035,6 +2046,7 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
}
nr_tids = get_tid_list(pos, tid_array, inode);
+ inode->i_nlink = pos + nr_tids;
for (i = 0; i < nr_tids; i++) {
unsigned long j = PROC_NUMBUF;
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index a4e2ed544bbe..49c479c9454a 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -260,8 +260,9 @@ static inline int block_group_used(struct super_block *s, u32 id) {
/*
* the packing is returned in disk byte order
*/
-u32 reiserfs_choose_packing(struct inode *dir) {
- u32 packing;
+__le32 reiserfs_choose_packing(struct inode *dir)
+{
+ __le32 packing;
if (TEST_OPTION(packing_groups, dir->i_sb)) {
u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
/*
@@ -655,7 +656,7 @@ static int get_left_neighbor(reiserfs_blocknr_hint_t *hint)
struct buffer_head * bh;
struct item_head * ih;
int pos_in_item;
- __u32 * item;
+ __le32 * item;
int ret = 0;
if (!hint->path) /* reiserfs code can call this function w/o pointer to path
@@ -736,7 +737,7 @@ static inline int this_blocknr_allocation_would_make_it_a_large_file(reiserfs_bl
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
static inline void displace_new_packing_locality (reiserfs_blocknr_hint_t *hint)
{
- struct reiserfs_key * key = &hint->key;
+ struct in_core_key * key = &hint->key;
hint->th->displace_new_blocks = 0;
hint->search_start = hint->beg + keyed_hash((char*)(&key->k_objectid),4) % (hint->end - hint->beg);
@@ -777,7 +778,7 @@ static inline int old_way (reiserfs_blocknr_hint_t * hint)
static inline void hundredth_slices (reiserfs_blocknr_hint_t * hint)
{
- struct reiserfs_key * key = &hint->key;
+ struct in_core_key * key = &hint->key;
b_blocknr_t slice_start;
slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100);
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index d1514a9b0514..fbde4b01a325 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -209,8 +209,8 @@ static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldi
/* compose directory item containing "." and ".." entries (entries are
not aligned to 4 byte boundary) */
/* the last four params are LE */
-void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
- __u32 par_dirid, __u32 par_objid)
+void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid)
{
struct reiserfs_de_head * deh;
@@ -242,8 +242,8 @@ void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
}
/* compose directory item containing "." and ".." entries */
-void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
- __u32 par_dirid, __u32 par_objid)
+void make_empty_dir_item (char * body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid)
{
struct reiserfs_de_head * deh;
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 26950113af8c..2230afff1870 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -166,7 +166,7 @@ static int reiserfs_allocate_blocks_for_region(
struct cpu_key key; // cpu key of item that we are going to deal with
struct item_head *ih; // pointer to item head that we are going to deal with
struct buffer_head *bh; // Buffer head that contains items that we are going to deal with
- __u32 * item; // pointer to item we are going to deal with
+ __le32 * item; // pointer to item we are going to deal with
INITIALIZE_PATH(path); // path to item, that we are going to deal with.
b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored.
reiserfs_blocknr_hint_t hint; // hint structure for block allocator.
@@ -891,7 +891,7 @@ static int reiserfs_prepare_file_region_for_write(
struct item_head *ih = NULL; // pointer to item head that we are going to deal with
struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with
INITIALIZE_PATH(path); // path to item, that we are going to deal with.
- __u32 * item=NULL; // pointer to item we are going to deal with
+ __le32 * item=NULL; // pointer to item we are going to deal with
int item_pos=-1; /* Position in indirect item */
@@ -1284,10 +1284,11 @@ static ssize_t reiserfs_file_write( struct file *file, /* the file we are going
reiserfs_claim_blocks_to_be_allocated(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits));
reiserfs_write_unlock(inode->i_sb);
- if ( !num_pages ) { /* If we do not have enough space even for */
- res = -ENOSPC; /* single page, return -ENOSPC */
- if ( pos > (inode->i_size & (inode->i_sb->s_blocksize-1)))
- break; // In case we are writing past the file end, break.
+ if ( !num_pages ) { /* If we do not have enough space even for a single page... */
+ if ( pos > inode->i_size+inode->i_sb->s_blocksize-(pos & (inode->i_sb->s_blocksize-1))) {
+ res = -ENOSPC;
+ break; // In case we are writing past the end of the last file block, break.
+ }
// Otherwise we are possibly overwriting the file, so
// let's set write size to be equal or less than blocksize.
// This way we get it correctly for file holes.
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 7543031396f4..2711dff1b7b4 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -173,7 +173,7 @@ static inline void fix_tail_page_for_writing(struct page *page) {
done already or non-hole position has been found in the indirect item */
static inline int allocation_needed (int retval, b_blocknr_t allocated,
struct item_head * ih,
- __u32 * item, int pos_in_item)
+ __le32 * item, int pos_in_item)
{
if (allocated)
return 0;
@@ -278,7 +278,7 @@ research:
bh = get_last_bh (&path);
ih = get_ih (&path);
if (is_indirect_le_ih (ih)) {
- __u32 * ind_item = (__u32 *)B_I_PITEM (bh, ih);
+ __le32 * ind_item = (__le32 *)B_I_PITEM (bh, ih);
/* FIXME: here we could cache indirect item or part of it in
the inode to avoid search_by_key in case of subsequent
@@ -581,7 +581,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
struct cpu_key key;
struct buffer_head * bh, * unbh = NULL;
struct item_head * ih, tmp_ih;
- __u32 * item;
+ __le32 * item;
int done;
int fs_gen;
struct reiserfs_transaction_handle *th = NULL;
@@ -746,7 +746,7 @@ start_trans:
done = 0;
do {
if (is_statdata_le_ih (ih)) {
- __u32 unp = 0;
+ __le32 unp = 0;
struct cpu_key tmp_key;
/* indirect item has to be inserted */
@@ -1341,8 +1341,8 @@ void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args
key.version = KEY_FORMAT_3_5;
key.on_disk_key.k_dir_id = dirino;
key.on_disk_key.k_objectid = inode->i_ino;
- key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET;
- key.on_disk_key.u.k_offset_v1.k_uniqueness = SD_UNIQUENESS;
+ key.on_disk_key.k_offset = 0;
+ key.on_disk_key.k_type = 0;
/* look for the object's stat data */
retval = search_item (inode->i_sb, &key, &path_to_sd);
@@ -2067,7 +2067,7 @@ static int map_block_for_writepage(struct inode *inode,
struct item_head tmp_ih ;
struct item_head *ih ;
struct buffer_head *bh ;
- __u32 *item ;
+ __le32 *item ;
struct cpu_key key ;
INITIALIZE_PATH(path) ;
int pos_in_item ;
diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c
index 9cf7c13b120d..0ce33db1acdf 100644
--- a/fs/reiserfs/item_ops.c
+++ b/fs/reiserfs/item_ops.c
@@ -296,10 +296,11 @@ static void print_sequence (__u32 start, int len)
static void indirect_print_item (struct item_head * ih, char * item)
{
int j;
- __u32 * unp, prev = INT_MAX;
+ __le32 * unp;
+ __u32 prev = INT_MAX;
int num;
- unp = (__u32 *)item;
+ unp = (__le32 *)item;
if (ih_item_len(ih) % UNFM_P_SIZE)
reiserfs_warning (NULL, "indirect_print_item: invalid item len");
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index c9ad3a7849f4..3072cfdee959 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2306,13 +2306,16 @@ static int journal_init_dev( struct super_block *super,
if( !IS_ERR( journal -> j_dev_file ) ) {
struct inode *jdev_inode = journal->j_dev_file->f_mapping->host;
if( !S_ISBLK( jdev_inode -> i_mode ) ) {
- reiserfs_warning (super, "journal_init_dev: '%s' is "
- "not a block device", jdev_name );
+ reiserfs_warning(super, "journal_init_dev: '%s' is "
+ "not a block device", jdev_name );
result = -ENOTBLK;
+ release_journal_dev( super, journal );
} else {
/* ok */
journal->j_dev_bd = I_BDEV(jdev_inode);
set_blocksize(journal->j_dev_bd, super->s_blocksize);
+ reiserfs_info(super, "journal_init_dev: journal device: %s\n",
+ bdevname(journal->j_dev_bd, b));
}
} else {
result = PTR_ERR( journal -> j_dev_file );
@@ -2321,11 +2324,6 @@ static int journal_init_dev( struct super_block *super,
"journal_init_dev: Cannot open '%s': %i",
jdev_name, result );
}
- if( result != 0 ) {
- release_journal_dev( super, journal );
- }
- reiserfs_info(super, "journal_init_dev: journal device: %s\n",
- bdevname(journal->j_dev_bd, b));
return result;
}
@@ -2393,7 +2391,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
jh = (struct reiserfs_journal_header *)(bhjh->b_data);
/* make sure that journal matches to the super block */
- if (is_reiserfs_jr(rs) && (jh->jh_journal.jp_journal_magic != sb_jp_journal_magic(rs))) {
+ if (is_reiserfs_jr(rs) && (le32_to_cpu(jh->jh_journal.jp_journal_magic) != sb_jp_journal_magic(rs))) {
reiserfs_warning (p_s_sb, "sh-460: journal header magic %x "
"(device %s) does not match to magic found in super "
"block %x",
diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c
index 0785c43a7486..bfe8e25ef293 100644
--- a/fs/reiserfs/objectid.c
+++ b/fs/reiserfs/objectid.c
@@ -11,13 +11,13 @@
// find where objectid map starts
#define objectid_map(s,rs) (old_format_only (s) ? \
- (__u32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
- (__u32 *)((rs) + 1))
+ (__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
+ (__le32 *)((rs) + 1))
#ifdef CONFIG_REISERFS_CHECK
-static void check_objectid_map (struct super_block * s, __u32 * map)
+static void check_objectid_map (struct super_block * s, __le32 * map)
{
if (le32_to_cpu (map[0]) != 1)
reiserfs_panic (s, "vs-15010: check_objectid_map: map corrupted: %lx",
@@ -27,7 +27,7 @@ static void check_objectid_map (struct super_block * s, __u32 * map)
}
#else
-static void check_objectid_map (struct super_block * s, __u32 * map)
+static void check_objectid_map (struct super_block * s, __le32 * map)
{;}
#endif
@@ -52,7 +52,7 @@ __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th)
{
struct super_block * s = th->t_super;
struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
- __u32 * map = objectid_map (s, rs);
+ __le32 * map = objectid_map (s, rs);
__u32 unused_objectid;
BUG_ON (!th->t_trans_id);
@@ -97,7 +97,7 @@ void reiserfs_release_objectid (struct reiserfs_transaction_handle *th,
{
struct super_block * s = th->t_super;
struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
- __u32 * map = objectid_map (s, rs);
+ __le32 * map = objectid_map (s, rs);
int i = 0;
BUG_ON (!th->t_trans_id);
@@ -172,12 +172,12 @@ int reiserfs_convert_objectid_map_v1(struct super_block *s) {
int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2 ;
int old_max = sb_oid_maxsize(disk_sb);
struct reiserfs_super_block_v1 *disk_sb_v1 ;
- __u32 *objectid_map, *new_objectid_map ;
+ __le32 *objectid_map, *new_objectid_map ;
int i ;
disk_sb_v1=(struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
- objectid_map = (__u32 *)(disk_sb_v1 + 1) ;
- new_objectid_map = (__u32 *)(disk_sb + 1) ;
+ objectid_map = (__le32 *)(disk_sb_v1 + 1) ;
+ new_objectid_map = (__le32 *)(disk_sb + 1) ;
if (cur_size > new_size) {
/* mark everyone used that was listed as free at the end of the objectid
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index f4ea81ae0e0f..e242ebc7f6f6 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -73,8 +73,8 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
#define DFL( x ) D4C( rs -> s_v1.x )
#define objectid_map( s, rs ) (old_format_only (s) ? \
- (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1) : \
- (__u32 *)(rs + 1))
+ (__le32 *)((struct reiserfs_super_block_v1 *)rs + 1) : \
+ (__le32 *)(rs + 1))
#define MAP( i ) D4C( objectid_map( sb, rs )[ i ] )
#define DJF( x ) le32_to_cpu( rs -> x )
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index 73ec5212178b..da23ba75f3d5 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -87,22 +87,20 @@ inline void copy_item_head(struct item_head * p_v_to,
inline int comp_short_keys (const struct reiserfs_key * le_key,
const struct cpu_key * cpu_key)
{
- __u32 * p_s_le_u32, * p_s_cpu_u32;
- int n_key_length = REISERFS_SHORT_KEY_LEN;
-
- p_s_le_u32 = (__u32 *)le_key;
- p_s_cpu_u32 = (__u32 *)&cpu_key->on_disk_key;
- for( ; n_key_length--; ++p_s_le_u32, ++p_s_cpu_u32 ) {
- if ( le32_to_cpu (*p_s_le_u32) < *p_s_cpu_u32 )
+ __u32 n;
+ n = le32_to_cpu(le_key->k_dir_id);
+ if (n < cpu_key->on_disk_key.k_dir_id)
return -1;
- if ( le32_to_cpu (*p_s_le_u32) > *p_s_cpu_u32 )
+ if (n > cpu_key->on_disk_key.k_dir_id)
+ return 1;
+ n = le32_to_cpu(le_key->k_objectid);
+ if (n < cpu_key->on_disk_key.k_objectid)
+ return -1;
+ if (n > cpu_key->on_disk_key.k_objectid)
return 1;
- }
-
return 0;
}
-
/* k1 is pointer to on-disk structure which is stored in little-endian
form. k2 is pointer to cpu variable.
Compare keys using all 4 key fields.
@@ -152,18 +150,15 @@ inline int comp_short_le_keys (const struct reiserfs_key * key1, const struct re
inline void le_key2cpu_key (struct cpu_key * to, const struct reiserfs_key * from)
{
+ int version;
to->on_disk_key.k_dir_id = le32_to_cpu (from->k_dir_id);
to->on_disk_key.k_objectid = le32_to_cpu (from->k_objectid);
// find out version of the key
- to->version = le_key_version (from);
- if (to->version == KEY_FORMAT_3_5) {
- to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset);
- to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness);
- } else {
- to->on_disk_key.u.k_offset_v2.k_offset = offset_v2_k_offset(&from->u.k_offset_v2);
- to->on_disk_key.u.k_offset_v2.k_type = offset_v2_k_type(&from->u.k_offset_v2);
- }
+ version = le_key_version (from);
+ to->version = version;
+ to->on_disk_key.k_offset = le_key_k_offset(version, from);
+ to->on_disk_key.k_type = le_key_k_type(version, from);
}
@@ -228,8 +223,14 @@ extern struct tree_balance * cur_tb;
const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}};
/* Maximal possible key. It is never in the tree. */
-const struct reiserfs_key MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}};
+const struct reiserfs_key MAX_KEY = {
+ __constant_cpu_to_le32(0xffffffff),
+ __constant_cpu_to_le32(0xffffffff),
+ {{__constant_cpu_to_le32(0xffffffff),
+ __constant_cpu_to_le32(0xffffffff)},}
+};
+const struct in_core_key MAX_IN_CORE_KEY = {~0U, ~0U, ~0ULL>>4, 15};
/* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom
of the path, and going upwards. We must check the path's validity at each step. If the key is not in
@@ -997,7 +998,7 @@ static char prepare_for_delete_or_cut(
int n_unfm_number, /* Number of the item unformatted nodes. */
n_counter,
n_blk_size;
- __u32 * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
+ __le32 * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
__u32 tmp;
struct item_head s_ih; /* Item header. */
char c_mode; /* Returned mode of the balance. */
@@ -1059,7 +1060,7 @@ static char prepare_for_delete_or_cut(
/* pointers to be cut */
n_unfm_number -= pos_in_item (p_s_path);
/* Set pointer to the last unformatted node pointer that is to be cut. */
- p_n_unfm_pointer = (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed;
+ p_n_unfm_pointer = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed;
/* We go through the unformatted nodes pointers of the indirect
@@ -1081,8 +1082,8 @@ static char prepare_for_delete_or_cut(
need_research = 1 ;
break;
}
- RFALSE( p_n_unfm_pointer < (__u32 *)B_I_PITEM(p_s_bh, &s_ih) ||
- p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
+ RFALSE( p_n_unfm_pointer < (__le32 *)B_I_PITEM(p_s_bh, &s_ih) ||
+ p_n_unfm_pointer > (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
"vs-5265: pointer out of range");
/* Hole, nothing to remove. */
@@ -1431,7 +1432,7 @@ int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode
#if defined( USE_INODE_GENERATION_COUNTER )
if( !old_format_only ( th -> t_super ) )
{
- __u32 *inode_generation;
+ __le32 *inode_generation;
inode_generation =
&REISERFS_SB(th -> t_super) -> s_rs -> s_inode_generation;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index bcdf2438d152..31e75125f48b 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -110,7 +110,7 @@ static void reiserfs_unlockfs(struct super_block *s) {
reiserfs_allow_writes(s) ;
}
-extern const struct reiserfs_key MAX_KEY;
+extern const struct in_core_key MAX_IN_CORE_KEY;
/* this is used to delete "save link" when there are no items of a
@@ -164,7 +164,7 @@ static int finish_unfinished (struct super_block * s)
/* compose key to look for "save" links */
max_cpu_key.version = KEY_FORMAT_3_5;
- max_cpu_key.on_disk_key = MAX_KEY;
+ max_cpu_key.on_disk_key = MAX_IN_CORE_KEY;
max_cpu_key.key_length = 3;
#ifdef CONFIG_QUOTA
@@ -216,10 +216,10 @@ static int finish_unfinished (struct super_block * s)
/* reiserfs_iget needs k_dirid and k_objectid only */
item = B_I_PITEM (bh, ih);
- obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item);
+ obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__le32 *)item);
obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid);
- obj_key.on_disk_key.u.k_offset_v1.k_offset = 0;
- obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0;
+ obj_key.on_disk_key.k_offset = 0;
+ obj_key.on_disk_key.k_type = 0;
pathrelse (&path);
@@ -304,7 +304,7 @@ void add_save_link (struct reiserfs_transaction_handle * th,
int retval;
struct cpu_key key;
struct item_head ih;
- __u32 link;
+ __le32 link;
BUG_ON (!th->t_trans_id);
@@ -889,12 +889,18 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
char * p;
p = NULL;
- /* "resize=NNN" */
- *blocks = simple_strtoul (arg, &p, 0);
- if (*p != '\0') {
- /* NNN does not look like a number */
- reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
- return 0;
+ /* "resize=NNN" or "resize=auto" */
+
+ if (!strcmp(arg, "auto")) {
+ /* From JFS code, to auto-get the size.*/
+ *blocks = s->s_bdev->bd_inode->i_size >> s->s_blocksize_bits;
+ } else {
+ *blocks = simple_strtoul (arg, &p, 0);
+ if (*p != '\0') {
+ /* NNN does not look like a number */
+ reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
+ return 0;
+ }
}
}
@@ -903,7 +909,8 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
unsigned long val = simple_strtoul (arg, &p, 0);
/* commit=NNN (time in seconds) */
if ( *p != '\0' || val >= (unsigned int)-1) {
- reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg); return 0;
+ reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
+ return 0;
}
*commit_max_age = (unsigned int)val;
}
@@ -1329,7 +1336,7 @@ static int read_super_block (struct super_block * s, int offset)
return 1;
}
- if ( rs->s_v1.s_root_block == -1 ) {
+ if ( rs->s_v1.s_root_block == cpu_to_le32(-1) ) {
brelse(bh) ;
reiserfs_warning (s, "Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
"reiserfsck --rebuild-tree and wait for a completion. If that fails\n"
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 650c43ba86c4..38ef913767ff 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -51,7 +51,10 @@ EXPORT_SYMBOL(seq_open);
/**
* seq_read - ->read() method for sequential files.
- * @file, @buf, @size, @ppos: see file_operations method
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @size: the maximum number of bytes to read
+ * @ppos: the current position in the file
*
* Ready-made ->f_op->read()
*/
@@ -219,7 +222,9 @@ Eoverflow:
/**
* seq_lseek - ->llseek() method for sequential files.
- * @file, @offset, @origin: see file_operations method
+ * @file: the file in question
+ * @offset: new position
+ * @origin: 0 for absolute, 1 for relative position
*
* Ready-made ->f_op->llseek()
*/
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index da25aeb0e062..364208071e17 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -96,7 +96,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
/**
* flush_read_buffer - push buffer to userspace.
* @buffer: data buffer for file.
- * @userbuf: user-passed buffer.
+ * @buf: user-passed buffer.
* @count: number of bytes requested.
* @ppos: file position.
*
@@ -164,7 +164,7 @@ out:
/**
* fill_write_buffer - copy buffer from userspace.
* @buffer: data buffer for file.
- * @userbuf: data from user.
+ * @buf: data from user.
* @count: number of bytes in @userbuf.
*
* Allocate @buffer->page if it hasn't been already, then
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 2faa4172b9f7..bb40d63f328f 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -49,8 +49,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page)
struct inode *inode = page->mapping->host;
char *kaddr;
- if (!PageLocked(page))
- PAGE_BUG(page);
+ BUG_ON(!PageLocked(page));
kaddr = kmap(page);
memset(kaddr, 0, PAGE_CACHE_SIZE);
@@ -67,8 +66,7 @@ static int udf_adinicb_writepage(struct page *page, struct writeback_control *wb
struct inode *inode = page->mapping->host;
char *kaddr;
- if (!PageLocked(page))
- PAGE_BUG(page);
+ BUG_ON(!PageLocked(page));
kaddr = kmap(page);
memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 0506e1173784..3d68de39fad6 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -167,8 +167,8 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
}
page = grab_cache_page(inode->i_mapping, 0);
- if (!PageLocked(page))
- PAGE_BUG(page);
+ BUG_ON(!PageLocked(page));
+
if (!PageUptodate(page))
{
kaddr = kmap(page);