summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-01-10 05:27:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-01-10 05:27:25 +0000
commitc9c06167e7933d93a6e396174c68abf242294abb (patch)
treed9a8bb30663e9a3405a1ef37ffb62bc14b9f019f /fs
parentf79e8cc3c34e4192a3e5ef4cc9c6542fdef703c0 (diff)
Merge with Linux 2.4.0-test12.
Diffstat (limited to 'fs')
-rw-r--r--fs/adfs/inode.c2
-rw-r--r--fs/affs/file.c2
-rw-r--r--fs/bfs/file.c2
-rw-r--r--fs/bfs/inode.c1
-rw-r--r--fs/binfmt_elf.c6
-rw-r--r--fs/buffer.c445
-rw-r--r--fs/dquot.c4
-rw-r--r--fs/exec.c2
-rw-r--r--fs/ext2/fsync.c130
-rw-r--r--fs/ext2/ialloc.c60
-rw-r--r--fs/ext2/inode.c12
-rw-r--r--fs/ext2/namei.c34
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/file.c4
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/hfs/inode.c2
-rw-r--r--fs/hpfs/buffer.c4
-rw-r--r--fs/hpfs/file.c2
-rw-r--r--fs/inode.c81
-rw-r--r--fs/isofs/dir.c10
-rw-r--r--fs/isofs/inode.c257
-rw-r--r--fs/isofs/namei.c20
-rw-r--r--fs/isofs/rock.c47
-rw-r--r--fs/isofs/util.c2
-rw-r--r--fs/lockd/clntproc.c2
-rw-r--r--fs/locks.c13
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/namei.c22
-rw-r--r--fs/ncpfs/Config.in2
-rw-r--r--fs/ncpfs/ioctl.c4
-rw-r--r--fs/ncpfs/ncplib_kernel.h6
-rw-r--r--fs/nfs/dir.c189
-rw-r--r--fs/nfs/file.c19
-rw-r--r--fs/nfs/inode.c242
-rw-r--r--fs/nfs/nfs3proc.c127
-rw-r--r--fs/nfs/proc.c87
-rw-r--r--fs/nfs/read.c65
-rw-r--r--fs/nfs/symlink.c16
-rw-r--r--fs/nfs/write.c152
-rw-r--r--fs/ntfs/fs.c26
-rw-r--r--fs/proc/generic.c3
-rw-r--r--fs/proc/root.c1
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/ramfs/inode.c2
-rw-r--r--fs/readdir.c1
-rw-r--r--fs/smbfs/dir.c6
-rw-r--r--fs/smbfs/file.c54
-rw-r--r--fs/smbfs/inode.c18
-rw-r--r--fs/smbfs/proc.c21
-rw-r--r--fs/smbfs/sock.c4
-rw-r--r--fs/stat.c8
-rw-r--r--fs/super.c10
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/udf/inode.c4
-rw-r--r--fs/ufs/inode.c2
56 files changed, 1077 insertions, 1170 deletions
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 42f19e292..161122650 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -53,7 +53,7 @@ abort_toobig:
return 0;
}
-static int adfs_writepage(struct file *file, struct page *page)
+static int adfs_writepage(struct page *page)
{
return block_write_full_page(page, adfs_get_block);
}
diff --git a/fs/affs/file.c b/fs/affs/file.c
index de0808b9e..341660c4b 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -338,7 +338,7 @@ abort_negative:
}
-static int affs_writepage(struct file *file, struct page *page)
+static int affs_writepage(struct page *page)
{
return block_write_full_page(page,affs_get_block);
}
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index f0ee10a15..de63fb2de 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -135,7 +135,7 @@ out:
return err;
}
-static int bfs_writepage(struct file *file, struct page *page)
+static int bfs_writepage(struct page *page)
{
return block_write_full_page(page, bfs_get_block);
}
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index b3827a7ae..8e33b4ab2 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -77,7 +77,6 @@ static void bfs_read_inode(struct inode * inode)
inode->i_atime = di->i_atime;
inode->i_mtime = di->i_mtime;
inode->i_ctime = di->i_ctime;
- inode->i_rdev = 0; /* BFS doesn't have special nodes */
inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
inode->iu_sblock = di->i_sblock;
inode->iu_eblock = di->i_eblock;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 861ede356..c84164fc4 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -247,7 +247,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
goto out;
if (!elf_check_arch(interp_elf_ex))
goto out;
- if (!interpreter->f_op->mmap)
+ if (!interpreter->f_op || !interpreter->f_op->mmap)
goto out;
/*
@@ -364,7 +364,7 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
do_brk(0, text_data);
retval = -ENOEXEC;
- if (!interpreter->f_op->read)
+ if (!interpreter->f_op || !interpreter->f_op->read)
goto out;
retval = interpreter->f_op->read(interpreter, addr, text_data, &offset);
if (retval < 0)
@@ -789,7 +789,7 @@ static int load_elf_library(struct file *file)
/* First of all, some simple consistency checks */
if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(&elf_ex) || !file->f_op->mmap)
+ !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap)
goto out;
/* Now read in all of the header information */
diff --git a/fs/buffer.c b/fs/buffer.c
index 9f9fbbfbd..8e2a382c3 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -69,6 +69,8 @@ static char buffersize_index[65] =
* lru_list_lock > hash_table_lock > free_list_lock > unused_list_lock
*/
+#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
+
/*
* Hash table gook..
*/
@@ -567,6 +569,42 @@ unsigned int get_hardblocksize(kdev_t dev)
return 0;
}
+void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+ spin_lock(&lru_list_lock);
+ if (bh->b_inode)
+ list_del(&bh->b_inode_buffers);
+ bh->b_inode = inode;
+ list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
+ spin_unlock(&lru_list_lock);
+}
+
+/* The caller must have the lru_list lock before calling the
+ remove_inode_queue functions. */
+static void __remove_inode_queue(struct buffer_head *bh)
+{
+ bh->b_inode = NULL;
+ list_del(&bh->b_inode_buffers);
+}
+
+static inline void remove_inode_queue(struct buffer_head *bh)
+{
+ if (bh->b_inode)
+ __remove_inode_queue(bh);
+}
+
+int inode_has_buffers(struct inode *inode)
+{
+ int ret;
+
+ spin_lock(&lru_list_lock);
+ ret = !list_empty(&inode->i_dirty_buffers);
+ spin_unlock(&lru_list_lock);
+
+ return ret;
+}
+
+
/* If invalidate_buffers() will trash dirty buffers, it means some kind
of fs corruption is going on. Trashing dirty data always imply losing
information that was supposed to be just stored on the physical layer
@@ -615,6 +653,7 @@ void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
write_lock(&hash_table_lock);
if (!atomic_read(&bh->b_count) &&
(destroy_dirty_buffers || !buffer_dirty(bh))) {
+ remove_inode_queue(bh);
__remove_from_queues(bh);
put_last_free(bh);
}
@@ -679,6 +718,7 @@ void set_blocksize(kdev_t dev, int size)
printk(KERN_WARNING
"set_blocksize: dev %s buffer_dirty %lu size %hu\n",
kdevname(dev), bh->b_blocknr, bh->b_size);
+ remove_inode_queue(bh);
__remove_from_queues(bh);
put_last_free(bh);
} else {
@@ -718,12 +758,6 @@ void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
bh->b_private = private;
}
-static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
-{
- mark_buffer_uptodate(bh, uptodate);
- unlock_buffer(bh);
-}
-
static void end_buffer_io_bad(struct buffer_head *bh, int uptodate)
{
mark_buffer_uptodate(bh, uptodate);
@@ -794,6 +828,137 @@ still_busy:
}
/*
+ * Synchronise all the inode's dirty buffers to the disk.
+ *
+ * We have conflicting pressures: we want to make sure that all
+ * initially dirty buffers get waited on, but that any subsequently
+ * dirtied buffers don't. After all, we don't want fsync to last
+ * forever if somebody is actively writing to the file.
+ *
+ * Do this in two main stages: first we copy dirty buffers to a
+ * temporary inode list, queueing the writes as we go. Then we clean
+ * up, waiting for those writes to complete.
+ *
+ * During this second stage, any subsequent updates to the file may end
+ * up refiling the buffer on the original inode's dirty list again, so
+ * there is a chance we will end up with a buffer queued for write but
+ * not yet completed on that list. So, as a final cleanup we go through
+ * the osync code to catch these locked, dirty buffers without requeuing
+ * any newly dirty buffers for write.
+ */
+
+int fsync_inode_buffers(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct inode tmp;
+ int err = 0, err2;
+
+ INIT_LIST_HEAD(&tmp.i_dirty_buffers);
+
+ spin_lock(&lru_list_lock);
+
+ while (!list_empty(&inode->i_dirty_buffers)) {
+ bh = BH_ENTRY(inode->i_dirty_buffers.next);
+ list_del(&bh->b_inode_buffers);
+ if (!buffer_dirty(bh) && !buffer_locked(bh))
+ bh->b_inode = NULL;
+ else {
+ bh->b_inode = &tmp;
+ list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
+ if (buffer_dirty(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ ll_rw_block(WRITE, 1, &bh);
+ brelse(bh);
+ spin_lock(&lru_list_lock);
+ }
+ }
+ }
+
+ while (!list_empty(&tmp.i_dirty_buffers)) {
+ bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
+ remove_inode_queue(bh);
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ err = -EIO;
+ brelse(bh);
+ spin_lock(&lru_list_lock);
+ }
+
+ spin_unlock(&lru_list_lock);
+ err2 = osync_inode_buffers(inode);
+
+ if (err)
+ return err;
+ else
+ return err2;
+}
+
+
+/*
+ * osync is designed to support O_SYNC io. It waits synchronously for
+ * all already-submitted IO to complete, but does not queue any new
+ * writes to the disk.
+ *
+ * To do O_SYNC writes, just queue the buffer writes with ll_rw_block as
+ * you dirty the buffers, and then use osync_inode_buffers to wait for
+ * completion. Any other dirty buffers which are not yet queued for
+ * write will not be flushed to disk by the osync.
+ */
+
+int osync_inode_buffers(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct list_head *list;
+ int err = 0;
+
+ spin_lock(&lru_list_lock);
+
+ repeat:
+
+ for (list = inode->i_dirty_buffers.prev;
+ bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
+ list = bh->b_inode_buffers.prev) {
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ err = -EIO;
+ brelse(bh);
+ spin_lock(&lru_list_lock);
+ goto repeat;
+ }
+ }
+
+ spin_unlock(&lru_list_lock);
+ return err;
+}
+
+
+/*
+ * Invalidate any and all dirty buffers on a given inode. We are
+ * probably unmounting the fs, but that doesn't mean we have already
+ * done a sync(). Just drop the buffers from the inode list.
+ */
+void invalidate_inode_buffers(struct inode *inode)
+{
+ struct list_head *list, *next;
+
+ spin_lock(&lru_list_lock);
+ list = inode->i_dirty_buffers.next;
+ while (list != &inode->i_dirty_buffers) {
+ next = list->next;
+ remove_inode_queue(BH_ENTRY(list));
+ list = next;
+ }
+ spin_unlock(&lru_list_lock);
+}
+
+
+/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
* so it should be much more efficient than it looks.
@@ -830,7 +995,7 @@ repeat:
* and it is clean.
*/
if (bh) {
- init_buffer(bh, end_buffer_io_sync, NULL);
+ init_buffer(bh, end_buffer_io_bad, NULL);
bh->b_dev = dev;
bh->b_blocknr = block;
bh->b_state = 1 << BH_Mapped;
@@ -941,6 +1106,8 @@ static void __refile_buffer(struct buffer_head *bh)
if (dispose != bh->b_list) {
__remove_from_lru_list(bh, bh->b_list);
bh->b_list = dispose;
+ if (dispose == BUF_CLEAN)
+ remove_inode_queue(bh);
__insert_into_lru_list(bh, dispose);
}
}
@@ -978,6 +1145,7 @@ void __bforget(struct buffer_head * buf)
if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
goto in_use;
__hash_unlink(buf);
+ remove_inode_queue(buf);
write_unlock(&hash_table_lock);
__remove_from_lru_list(buf, buf->b_list);
spin_unlock(&lru_list_lock);
@@ -1009,71 +1177,12 @@ struct buffer_head * bread(kdev_t dev, int block, int size)
}
/*
- * Ok, breada can be used as bread, but additionally to mark other
- * blocks for reading as well. End the argument list with a negative
- * number.
- */
-
-#define NBUF 16
-
-struct buffer_head * breada(kdev_t dev, int block, int bufsize,
- unsigned int pos, unsigned int filesize)
-{
- struct buffer_head * bhlist[NBUF];
- unsigned int blocks;
- struct buffer_head * bh;
- int index;
- int i, j;
-
- if (pos >= filesize)
- return NULL;
-
- if (block < 0)
- return NULL;
-
- bh = getblk(dev, block, bufsize);
- index = BUFSIZE_INDEX(bh->b_size);
-
- if (buffer_uptodate(bh))
- return(bh);
- else ll_rw_block(READ, 1, &bh);
-
- blocks = (filesize - pos) >> (9+index);
-
- if (blocks > NBUF)
- blocks = NBUF;
-
- bhlist[0] = bh;
- j = 1;
- for(i=1; i<blocks; i++) {
- bh = getblk(dev,block+i,bufsize);
- if (buffer_uptodate(bh)) {
- brelse(bh);
- break;
- }
- else bhlist[j++] = bh;
- }
-
- /* Request the read for these buffers, and then release them. */
- if (j>1)
- ll_rw_block(READA, (j-1), bhlist+1);
- for(i=1; i<j; i++)
- brelse(bhlist[i]);
-
- /* Wait for this buffer, and then continue on. */
- bh = bhlist[0];
- wait_on_buffer(bh);
- if (buffer_uptodate(bh))
- return bh;
- brelse(bh);
- return NULL;
-}
-
-/*
* Note: the caller should wake up the buffer_wait list if needed.
*/
static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
{
+ if (bh->b_inode)
+ BUG();
if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
kmem_cache_free(bh_cachep, bh);
} else {
@@ -1241,40 +1350,6 @@ no_grow:
goto try_again;
}
-static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size)
-{
- struct buffer_head *head, *bh, *tail;
- int block;
-
- if (!PageLocked(page))
- BUG();
- /*
- * Allocate async buffer heads pointing to this page, just for I/O.
- * They don't show up in the buffer hash table, but they *are*
- * registered in page->buffers.
- */
- head = create_buffers(page, size, 1);
- if (page->buffers)
- BUG();
- if (!head)
- BUG();
- tail = head;
- for (bh = head; bh; bh = bh->b_this_page) {
- block = *(b++);
-
- tail = bh;
- init_buffer(bh, end_buffer_io_async, NULL);
- bh->b_dev = dev;
- bh->b_blocknr = block;
-
- set_bit(BH_Mapped, &bh->b_state);
- }
- tail->b_this_page = head;
- page_cache_get(page);
- page->buffers = head;
- return 0;
-}
-
static void unmap_buffer(struct buffer_head * bh)
{
if (buffer_mapped(bh)) {
@@ -1339,7 +1414,7 @@ int block_flushpage(struct page *page, unsigned long offset)
return 1;
}
-static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize)
+static void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize)
{
struct buffer_head *bh, *head, *tail;
@@ -1349,7 +1424,7 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
bh = head;
do {
- bh->b_dev = inode->i_dev;
+ bh->b_dev = dev;
bh->b_blocknr = 0;
bh->b_end_io = end_buffer_io_bad;
tail = bh;
@@ -1407,7 +1482,7 @@ static void unmap_underlying_metadata(struct buffer_head * bh)
*/
static int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block)
{
- int err, i, need_balance_dirty = 0;
+ int err, i;
unsigned long block;
struct buffer_head *bh, *head;
@@ -1415,13 +1490,15 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
BUG();
if (!page->buffers)
- create_empty_buffers(page, inode, inode->i_sb->s_blocksize);
+ create_empty_buffers(page, inode->i_dev, inode->i_sb->s_blocksize);
head = page->buffers;
block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
bh = head;
i = 0;
+
+ /* Stage 1: make sure we have all the buffers mapped! */
do {
/*
* If the buffer isn't up-to-date, we can't be sure
@@ -1431,7 +1508,6 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
* Leave it to the low-level FS to make all those
* decisions (block #0 may actually be a valid block)
*/
- bh->b_end_io = end_buffer_io_sync;
if (!buffer_mapped(bh)) {
err = get_block(inode, block, bh, 1);
if (err)
@@ -1439,23 +1515,33 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
if (buffer_new(bh))
unmap_underlying_metadata(bh);
}
- set_bit(BH_Uptodate, &bh->b_state);
- if (!atomic_set_buffer_dirty(bh)) {
- __mark_dirty(bh);
- need_balance_dirty = 1;
- }
-
bh = bh->b_this_page;
block++;
} while (bh != head);
- if (need_balance_dirty)
- balance_dirty(bh->b_dev);
+ /* Stage 2: lock the buffers, mark them dirty */
+ do {
+ lock_buffer(bh);
+ bh->b_end_io = end_buffer_io_async;
+ atomic_inc(&bh->b_count);
+ set_bit(BH_Uptodate, &bh->b_state);
+ set_bit(BH_Dirty, &bh->b_state);
+ bh = bh->b_this_page;
+ } while (bh != head);
+ /* Stage 3: submit the IO */
+ do {
+ submit_bh(WRITE, bh);
+ bh = bh->b_this_page;
+ } while (bh != head);
+
+ /* Done - end_buffer_io_async will unlock */
SetPageUptodate(page);
return 0;
+
out:
ClearPageUptodate(page);
+ UnlockPage(page);
return err;
}
@@ -1471,7 +1557,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
+ create_empty_buffers(page, inode->i_dev, blocksize);
head = page->buffers;
bbits = inode->i_sb->s_blocksize_bits;
@@ -1486,7 +1572,6 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
continue;
if (block_start >= to)
break;
- bh->b_end_io = end_buffer_io_sync;
if (!buffer_mapped(bh)) {
err = get_block(inode, block, bh, 1);
if (err)
@@ -1551,6 +1636,7 @@ static int __block_commit_write(struct inode *inode, struct page *page,
set_bit(BH_Uptodate, &bh->b_state);
if (!atomic_set_buffer_dirty(bh)) {
__mark_dirty(bh);
+ buffer_insert_inode_queue(bh, inode);
need_balance_dirty = 1;
}
}
@@ -1582,14 +1668,13 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
- char *kaddr = NULL;
int nr, i;
if (!PageLocked(page))
PAGE_BUG(page);
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
+ create_empty_buffers(page, inode->i_dev, blocksize);
head = page->buffers;
blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
@@ -1609,35 +1694,40 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
continue;
}
if (!buffer_mapped(bh)) {
- if (!kaddr)
- kaddr = kmap(page);
- memset(kaddr + i*blocksize, 0, blocksize);
+ memset(kmap(page) + i*blocksize, 0, blocksize);
flush_dcache_page(page);
+ kunmap(page);
set_bit(BH_Uptodate, &bh->b_state);
continue;
}
}
- init_buffer(bh, end_buffer_io_async, NULL);
- atomic_inc(&bh->b_count);
arr[nr] = bh;
nr++;
} while (i++, iblock++, (bh = bh->b_this_page) != head);
- if (nr) {
- if (Page_Uptodate(page))
- BUG();
- ll_rw_block(READ, nr, arr);
- } else {
+ if (!nr) {
/*
* all buffers are uptodate - we can set the page
* uptodate as well.
*/
SetPageUptodate(page);
UnlockPage(page);
+ return 0;
}
- if (kaddr)
- kunmap(page);
+
+ /* Stage two: lock the buffers */
+ for (i = 0; i < nr; i++) {
+ struct buffer_head * bh = arr[i];
+ lock_buffer(bh);
+ bh->b_end_io = end_buffer_io_async;
+ atomic_inc(&bh->b_count);
+ }
+
+ /* Stage 3: start the IO */
+ for (i = 0; i < nr; i++)
+ submit_bh(READ, arr[i]);
+
return 0;
}
@@ -1779,7 +1869,7 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t
goto out;
if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
+ create_empty_buffers(page, inode->i_dev, blocksize);
/* Find the buffer that contains "offset" */
bh = page->buffers;
@@ -1805,7 +1895,6 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t
if (Page_Uptodate(page))
set_bit(BH_Uptodate, &bh->b_state);
- bh->b_end_io = end_buffer_io_sync;
if (!buffer_uptodate(bh)) {
err = -EIO;
ll_rw_block(READ, 1, &bh);
@@ -1843,8 +1932,11 @@ int block_write_full_page(struct page *page, get_block_t *get_block)
/* things got complicated... */
offset = inode->i_size & (PAGE_CACHE_SIZE-1);
/* OK, are we completely out? */
- if (page->index >= end_index+1 || !offset)
+ if (page->index >= end_index+1 || !offset) {
+ UnlockPage(page);
return -EIO;
+ }
+
/* Sigh... will have to work, then... */
err = __block_prepare_write(inode, page, 0, offset, get_block);
if (!err) {
@@ -1853,6 +1945,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block)
__block_commit_write(inode,page,0,offset);
done:
kunmap(page);
+ UnlockPage(page);
return err;
}
ClearPageUptodate(page);
@@ -1947,7 +2040,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
int pageind;
int bhind;
int offset;
- int sectors = size>>9;
unsigned long blocknr;
struct kiobuf * iobuf = NULL;
struct page * map;
@@ -1999,9 +2091,8 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
tmp->b_this_page = tmp;
init_buffer(tmp, end_buffer_io_kiobuf, iobuf);
- tmp->b_rdev = tmp->b_dev = dev;
+ tmp->b_dev = dev;
tmp->b_blocknr = blocknr;
- tmp->b_rsector = blocknr*sectors;
tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req);
if (rw == WRITE) {
@@ -2015,7 +2106,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
atomic_inc(&iobuf->io_count);
- generic_make_request(rw, tmp);
+ submit_bh(rw, tmp);
/*
* Wait for IO if we have got too much
*/
@@ -2075,67 +2166,30 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
*/
int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size)
{
- struct buffer_head *head, *bh, *arr[MAX_BUF_PER_PAGE];
- int nr, fresh /* temporary debugging flag */, block;
+ struct buffer_head *head, *bh;
if (!PageLocked(page))
panic("brw_page: page not locked for I/O");
-// ClearPageError(page);
- /*
- * We pretty much rely on the page lock for this, because
- * create_page_buffers() might sleep.
- */
- fresh = 0;
- if (!page->buffers) {
- create_page_buffers(rw, page, dev, b, size);
- fresh = 1;
- }
+
if (!page->buffers)
- BUG();
+ create_empty_buffers(page, dev, size);
+ head = bh = page->buffers;
- head = page->buffers;
- bh = head;
- nr = 0;
+ /* Stage 1: lock all the buffers */
do {
- block = *(b++);
+ lock_buffer(bh);
+ bh->b_blocknr = *(b++);
+ set_bit(BH_Mapped, &bh->b_state);
+ bh->b_end_io = end_buffer_io_async;
+ atomic_inc(&bh->b_count);
+ bh = bh->b_this_page;
+ } while (bh != head);
- if (fresh && (atomic_read(&bh->b_count) != 0))
- BUG();
- if (rw == READ) {
- if (!fresh)
- BUG();
- if (!buffer_uptodate(bh)) {
- arr[nr++] = bh;
- atomic_inc(&bh->b_count);
- }
- } else { /* WRITE */
- if (!bh->b_blocknr) {
- if (!block)
- BUG();
- bh->b_blocknr = block;
- } else {
- if (!block)
- BUG();
- }
- set_bit(BH_Uptodate, &bh->b_state);
- set_bit(BH_Dirty, &bh->b_state);
- arr[nr++] = bh;
- atomic_inc(&bh->b_count);
- }
+ /* Stage 2: start the IO */
+ do {
+ submit_bh(rw, bh);
bh = bh->b_this_page;
} while (bh != head);
- if ((rw == READ) && nr) {
- if (Page_Uptodate(page))
- BUG();
- ll_rw_block(rw, nr, arr);
- } else {
- if (!nr && rw == READ) {
- SetPageUptodate(page);
- UnlockPage(page);
- }
- if (nr && (rw == WRITE))
- ll_rw_block(rw, nr, arr);
- }
return 0;
}
@@ -2313,9 +2367,10 @@ cleaned_buffers_try_again:
/* The buffer can be either on the regular
* queues or on the free list..
*/
- if (p->b_dev != B_FREE)
+ if (p->b_dev != B_FREE) {
+ remove_inode_queue(p);
__remove_from_queues(p);
- else
+ } else
__remove_from_free_list(p, index);
__put_unused_buffer_head(p);
} while (tmp != bh);
@@ -2481,9 +2536,9 @@ void wakeup_bdflush(int block)
return;
}
- /* kflushd can wakeup us before we have a chance to
+ /* bdflush can wakeup us before we have a chance to
go to sleep so we must be smart in handling
- this wakeup event from kflushd to avoid deadlocking in SMP
+ this wakeup event from bdflush to avoid deadlocking in SMP
(we are not holding any lock anymore in these two paths). */
__set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&bdflush_done, &wait);
@@ -2646,7 +2701,7 @@ int bdflush(void *sem)
tsk->session = 1;
tsk->pgrp = 1;
- strcpy(tsk->comm, "kflushd");
+ strcpy(tsk->comm, "bdflush");
bdflush_tsk = tsk;
/* avoid getting signals */
diff --git a/fs/dquot.c b/fs/dquot.c
index 1bcd12ceb..a63685d34 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -522,7 +522,7 @@ static inline struct dquot *find_best_free(void)
struct dquot *get_empty_dquot(void)
{
struct dquot *dquot;
- int shrink = 1; /* Number of times we should try to shrink dcache and icache */
+ int shrink = 8; /* Number of times we should try to shrink dcache and icache */
repeat:
dquot = find_best_free();
@@ -1474,7 +1474,7 @@ static int quota_on(struct super_block *sb, short type, char *path)
if (IS_ERR(f))
goto out_lock;
error = -EIO;
- if (!f->f_op->read && !f->f_op->write)
+ if (!f->f_op || (!f->f_op->read && !f->f_op->write))
goto out_f;
inode = f->f_dentry->d_inode;
error = -EACCES;
diff --git a/fs/exec.c b/fs/exec.c
index 1e24a4ace..f04fab7e3 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -604,6 +604,8 @@ int prepare_binprm(struct linux_binprm *bprm)
/* Huh? We had already checked for MAY_EXEC, WTF do we check this? */
if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
+ if (bprm->file->f_op == NULL)
+ return -EACCES;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 42ce44c65..8b2ecab41 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -28,98 +28,6 @@
#include <linux/smp_lock.h>
-#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
-#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
-
-static int sync_indirect(struct inode * inode, u32 * block, int wait)
-{
- struct buffer_head * bh;
-
- if (!*block)
- return 0;
- bh = get_hash_table(inode->i_dev, le32_to_cpu(*block), blocksize);
- if (!bh)
- return 0;
- if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
- /* There can be a parallell read(2) that started read-I/O
- on the buffer so we can't assume that there's been
- an I/O error without first waiting I/O completation. */
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- {
- brelse (bh);
- return -1;
- }
- }
- if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
- if (wait)
- /* when we return from fsync all the blocks
- must be _just_ stored on disk */
- wait_on_buffer(bh);
- brelse(bh);
- return 0;
- }
- ll_rw_block(WRITE, 1, &bh);
- atomic_dec(&bh->b_count);
- return 0;
-}
-
-static int sync_iblock(struct inode * inode, u32 * iblock,
- struct buffer_head ** bh, int wait)
-{
- int rc, tmp;
-
- *bh = NULL;
- tmp = le32_to_cpu(*iblock);
- if (!tmp)
- return 0;
- rc = sync_indirect(inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread(inode->i_dev, tmp, blocksize);
- if (!*bh)
- return -1;
- return 0;
-}
-
-static int sync_dindirect(struct inode * inode, u32 * diblock, int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = sync_iblock(inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_indirect(inode, ((u32 *) dind_bh->b_data) + i, wait);
- if (rc)
- err = rc;
- }
- brelse(dind_bh);
- return err;
-}
-
-static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait)
-{
- int i;
- struct buffer_head * tind_bh;
- int rc, err = 0;
-
- rc = sync_iblock(inode, tiblock, &tind_bh, wait);
- if (rc || !tind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_dindirect(inode, ((u32 *) tind_bh->b_data) + i, wait);
- if (rc)
- err = rc;
- }
- brelse(tind_bh);
- return err;
-}
-
/*
* File may be NULL when we are called. Perhaps we shouldn't
* even pass file to fsync ?
@@ -127,32 +35,20 @@ static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait)
int ext2_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
- int wait, err = 0;
struct inode *inode = dentry->d_inode;
+ return ext2_fsync_inode(inode, datasync);
+}
- lock_kernel();
- if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
- /*
- * Don't sync fast links!
- */
- goto skip;
-
- err = generic_buffer_fdatasync(inode, 0, ~0UL);
-
- for (wait=0; wait<=1; wait++)
- {
- err |= sync_indirect(inode,
- inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
- wait);
- err |= sync_dindirect(inode,
- inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
- wait);
- err |= sync_tindirect(inode,
- inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
- wait);
- }
-skip:
- err |= ext2_sync_inode (inode);
- unlock_kernel();
+int ext2_fsync_inode(struct inode *inode, int datasync)
+{
+ int err;
+
+ err = fsync_inode_buffers(inode);
+ if (!(inode->i_state & I_DIRTY))
+ return err;
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ return err;
+
+ err |= ext2_sync_inode(inode);
return err ? -EIO : 0;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index cf8fa5154..9e4a9b6b0 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -256,7 +256,7 @@ error_return:
* For other inodes, search forward from the parent directory\'s block
* group to find a free inode.
*/
-struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
+struct inode * ext2_new_inode (const struct inode * dir, int mode)
{
struct super_block * sb;
struct buffer_head * bh;
@@ -267,26 +267,22 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
struct ext2_group_desc * gdp;
struct ext2_group_desc * tmp;
struct ext2_super_block * es;
+ int err;
/* Cannot create files in a deleted directory */
- if (!dir || !dir->i_nlink) {
- *err = -EPERM;
- return NULL;
- }
+ if (!dir || !dir->i_nlink)
+ return ERR_PTR(-EPERM);
sb = dir->i_sb;
inode = new_inode(sb);
- if (!inode) {
- *err = -ENOMEM;
- return NULL;
- }
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
lock_super (sb);
es = sb->u.ext2_sb.s_es;
repeat:
gdp = NULL; i=0;
- *err = -ENOSPC;
if (S_ISDIR(mode)) {
avefreei = le32_to_cpu(es->s_free_inodes_count) /
sb->u.ext2_sb.s_groups_count;
@@ -365,18 +361,14 @@ repeat:
}
}
- if (!gdp) {
- unlock_super (sb);
- iput(inode);
- return NULL;
- }
+ err = -ENOSPC;
+ if (!gdp)
+ goto fail;
+
+ err = -EIO;
bitmap_nr = load_inode_bitmap (sb, i);
- if (bitmap_nr < 0) {
- unlock_super (sb);
- iput(inode);
- *err = -EIO;
- return NULL;
- }
+ if (bitmap_nr < 0)
+ goto fail;
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
@@ -397,11 +389,11 @@ repeat:
ext2_error (sb, "ext2_new_inode",
"Free inodes count corrupted in group %d",
i);
- if (sb->s_flags & MS_RDONLY) {
- unlock_super (sb);
- iput (inode);
- return NULL;
- }
+ /* Is it really ENOSPC? */
+ err = -ENOSPC;
+ if (sb->s_flags & MS_RDONLY)
+ goto fail;
+
gdp->bg_free_inodes_count = 0;
mark_buffer_dirty(bh2);
}
@@ -412,10 +404,8 @@ repeat:
ext2_error (sb, "ext2_new_inode",
"reserved inode or inode > inodes count - "
"block_group = %d,inode=%d", i, j);
- unlock_super (sb);
- iput (inode);
- *err = -EIO;
- return NULL;
+ err = -EIO;
+ goto fail;
}
gdp->bg_free_inodes_count =
cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
@@ -464,13 +454,15 @@ repeat:
sb->dq_op->drop(inode);
inode->i_nlink = 0;
iput(inode);
- *err = -EDQUOT;
- return NULL;
+ return ERR_PTR(-EDQUOT);
}
ext2_debug ("allocating inode %lu\n", inode->i_ino);
-
- *err = 0;
return inode;
+
+fail:
+ unlock_super(sb);
+ iput(inode);
+ return ERR_PTR(err);
}
unsigned long ext2_count_free_inodes (struct super_block * sb)
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 5852cef4c..658a06416 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -404,7 +404,7 @@ static int ext2_alloc_branch(struct inode *inode,
branch[n].p = (u32*) bh->b_data + offsets[n];
*branch[n].p = branch[n].key;
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, inode);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -469,7 +469,7 @@ static inline int ext2_splice_branch(struct inode *inode,
/* had we spliced it onto indirect block? */
if (where->bh) {
- mark_buffer_dirty(where->bh);
+ mark_buffer_dirty_inode(where->bh, inode);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &where->bh);
wait_on_buffer(where->bh);
@@ -591,7 +591,7 @@ struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, i
wait_on_buffer(bh);
memset(bh->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, inode);
}
return bh;
}
@@ -650,7 +650,7 @@ struct buffer_head * ext2_bread (struct inode * inode, int block,
return NULL;
}
-static int ext2_writepage(struct file *file, struct page *page)
+static int ext2_writepage(struct page *page)
{
return block_write_full_page(page,ext2_get_block);
}
@@ -907,7 +907,7 @@ void ext2_truncate (struct inode * inode)
if (partial == chain)
mark_inode_dirty(inode);
else
- mark_buffer_dirty(partial->bh);
+ mark_buffer_dirty_inode(partial->bh, inode);
ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
}
/* Clear the ends of indirect blocks on the shared branch */
@@ -916,7 +916,7 @@ void ext2_truncate (struct inode * inode)
partial->p + 1,
(u32*)partial->bh->b_data + addr_per_block,
(chain+n-1) - partial);
- mark_buffer_dirty(partial->bh);
+ mark_buffer_dirty_inode(partial->bh, inode);
if (IS_SYNC(inode)) {
ll_rw_block (WRITE, 1, &partial->bh);
wait_on_buffer (partial->bh);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 3c981f75c..59d3ef492 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -296,7 +296,7 @@ int ext2_add_entry (struct inode * dir, const char * name, int namelen,
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
dir->i_version = ++event;
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, dir);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -337,7 +337,7 @@ static int ext2_delete_entry (struct inode * dir,
else
de->inode = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh);
+ mark_buffer_dirty_inode(bh, dir);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
@@ -361,11 +361,9 @@ static int ext2_delete_entry (struct inode * dir,
*/
static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
{
- struct inode * inode;
- int err;
-
- inode = ext2_new_inode (dir, mode, &err);
- if (!inode)
+ struct inode * inode = ext2_new_inode (dir, mode);
+ int err = PTR_ERR(inode);
+ if (IS_ERR(inode))
return err;
inode->i_op = &ext2_file_inode_operations;
@@ -387,11 +385,10 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
- struct inode * inode;
- int err;
+ struct inode * inode = ext2_new_inode (dir, mode);
+ int err = PTR_ERR(inode);
- inode = ext2_new_inode (dir, mode, &err);
- if (!inode)
+ if (IS_ERR(inode))
return err;
inode->i_uid = current->fsuid;
@@ -421,8 +418,9 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
if (dir->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
- inode = ext2_new_inode (dir, S_IFDIR, &err);
- if (!inode)
+ inode = ext2_new_inode (dir, S_IFDIR);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
return err;
inode->i_op = &ext2_dir_inode_operations;
@@ -449,7 +447,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
strcpy (de->name, "..");
ext2_set_de_type(dir->i_sb, de, S_IFDIR);
inode->i_nlink = 2;
- mark_buffer_dirty(dir_block);
+ mark_buffer_dirty_inode(dir_block, dir);
brelse (dir_block);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
@@ -628,7 +626,9 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char *
if (l > dir->i_sb->s_blocksize)
return -ENAMETOOLONG;
- if (!(inode = ext2_new_inode (dir, S_IFLNK, &err)))
+ inode = ext2_new_inode (dir, S_IFLNK);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
return err;
inode->i_mode = S_IFLNK | S_IRWXUGO;
@@ -755,7 +755,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
EXT2_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
new_dir->i_version = ++event;
- mark_buffer_dirty(new_bh);
+ mark_buffer_dirty_inode(new_bh, new_dir);
if (IS_SYNC(new_dir)) {
ll_rw_block (WRITE, 1, &new_bh);
wait_on_buffer (new_bh);
@@ -786,7 +786,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- mark_buffer_dirty(dir_bh);
+ mark_buffer_dirty_inode(dir_bh, old_inode);
old_dir->i_nlink--;
mark_inode_dirty(old_dir);
if (new_inode) {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 7537ee569..82f58826d 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -735,7 +735,7 @@ static int is_exec(char *extension)
return 0;
}
-static int fat_writepage(struct file *file, struct page *page)
+static int fat_writepage(struct page *page)
{
return block_write_full_page(page,fat_get_block);
}
diff --git a/fs/file.c b/fs/file.c
index 2f8ea1918..84d0275cd 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -16,7 +16,7 @@
/*
- * Allocate an fd array, using __get_free_page() if possible.
+ * Allocate an fd array, using kmalloc or vmalloc.
* Note: the array isn't cleared at allocation time.
*/
struct file ** alloc_fd_array(int num)
@@ -125,7 +125,7 @@ out:
}
/*
- * Allocate an fdset array, using __get_free_page() if possible.
+ * Allocate an fdset array, using kmalloc or vmalloc.
* Note: the array isn't cleared at allocation time.
*/
fd_set * alloc_fdset(int num)
diff --git a/fs/file_table.c b/fs/file_table.c
index 09b28574d..7a935a739 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -40,13 +40,11 @@ struct file * get_empty_filp(void)
list_del(&f->f_list);
files_stat.nr_free_files--;
new_one:
- file_list_unlock();
memset(f, 0, sizeof(*f));
atomic_set(&f->f_count,1);
f->f_version = ++event;
f->f_uid = current->fsuid;
f->f_gid = current->fsgid;
- file_list_lock();
list_add(&f->f_list, &anon_list);
file_list_unlock();
return f;
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 56d1547e7..7414a4c29 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -220,7 +220,7 @@ int hfs_notify_change_hdr(struct dentry *dentry, struct iattr * attr)
return __hfs_notify_change(dentry, attr, HFS_HDR);
}
-static int hfs_writepage(struct file *file, struct page *page)
+static int hfs_writepage(struct page *page)
{
return block_write_full_page(page,hfs_get_block);
}
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
index 5f5ec196f..c7b63f358 100644
--- a/fs/hpfs/buffer.c
+++ b/fs/hpfs/buffer.c
@@ -127,7 +127,7 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head
if (!ahead || secno + ahead >= s->s_hpfs_fs_size)
*bhp = bh = bread(dev, secno, 512);
- else *bhp = bh = breada(dev, secno, 512, 0, (ahead + 1) << 9);
+ else *bhp = bh = bread(dev, secno, 512);
if (bh != NULL)
return bh->b_data;
else {
@@ -175,7 +175,7 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
if (!ahead || secno + 4 + ahead > s->s_hpfs_fs_size)
qbh->bh[0] = bh = bread(dev, secno, 512);
- else qbh->bh[0] = bh = breada(dev, secno, 512, 0, (ahead + 4) << 9);
+ else qbh->bh[0] = bh = bread(dev, secno, 512);
if (!bh)
goto bail0;
memcpy(data, bh->b_data, 512);
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index fb5f566e7..a9675ef54 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -93,7 +93,7 @@ int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_resu
return 0;
}
-static int hpfs_writepage(struct file *file, struct page *page)
+static int hpfs_writepage(struct page *page)
{
return block_write_full_page(page,hpfs_get_block);
}
diff --git a/fs/inode.c b/fs/inode.c
index 96e3664e5..abbc04f1c 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -77,7 +77,13 @@ static kmem_cache_t * inode_cachep;
#define alloc_inode() \
((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
-#define destroy_inode(inode) kmem_cache_free(inode_cachep, (inode))
+static void destroy_inode(struct inode *inode)
+{
+ if (!list_empty(&inode->i_dirty_buffers))
+ BUG();
+ kmem_cache_free(inode_cachep, (inode));
+}
+
/*
* These are initializations that only need to be done
@@ -96,6 +102,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
INIT_LIST_HEAD(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_data.pages);
INIT_LIST_HEAD(&inode->i_dentry);
+ INIT_LIST_HEAD(&inode->i_dirty_buffers);
sema_init(&inode->i_sem, 1);
sema_init(&inode->i_zombie, 1);
spin_lock_init(&inode->i_data.i_shared_lock);
@@ -122,14 +129,14 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
* Mark an inode as dirty. Callers should use mark_inode_dirty.
*/
-void __mark_inode_dirty(struct inode *inode)
+void __mark_inode_dirty(struct inode *inode, int flags)
{
struct super_block * sb = inode->i_sb;
if (sb) {
spin_lock(&inode_lock);
- if (!(inode->i_state & I_DIRTY)) {
- inode->i_state |= I_DIRTY;
+ if ((inode->i_state & flags) != flags) {
+ inode->i_state |= flags;
/* Only add valid (ie hashed) inodes to the dirty list */
if (!list_empty(&inode->i_hash)) {
list_del(&inode->i_list);
@@ -196,7 +203,8 @@ static inline void sync_one(struct inode *inode, int sync)
? &inode_in_use
: &inode_unused);
/* Set I_LOCK, reset I_DIRTY */
- inode->i_state ^= I_DIRTY | I_LOCK;
+ inode->i_state |= I_LOCK;
+ inode->i_state &= ~I_DIRTY;
spin_unlock(&inode_lock);
write_inode(inode, sync);
@@ -282,6 +290,60 @@ void write_inode_now(struct inode *inode, int sync)
}
/**
+ * generic_osync_inode - flush all dirty data for a given inode to disk
+ * @inode: inode to write
+ * @datasync: if set, don't bother flushing timestamps
+ *
+ * This can be called by file_write functions for files which have the
+ * O_SYNC flag set, to flush dirty writes to disk.
+ */
+
+int generic_osync_inode(struct inode *inode, int datasync)
+{
+ int err;
+
+ /*
+ * WARNING
+ *
+ * Currently, the filesystem write path does not pass the
+ * filp down to the low-level write functions. Therefore it
+ * is impossible for (say) __block_commit_write to know if
+ * the operation is O_SYNC or not.
+ *
+ * Ideally, O_SYNC writes would have the filesystem call
+ * ll_rw_block as it went to kick-start the writes, and we
+ * could call osync_inode_buffers() here to wait only for
+ * those IOs which have already been submitted to the device
+ * driver layer. As it stands, if we did this we'd not write
+ * anything to disk since our writes have not been queued by
+ * this point: they are still on the dirty LRU.
+ *
+ * So, currently we will call fsync_inode_buffers() instead,
+ * to flush _all_ dirty buffers for this inode to disk on
+ * every O_SYNC write, not just the synchronous I/Os. --sct
+ */
+
+#ifdef WRITERS_QUEUE_IO
+ err = osync_inode_buffers(inode);
+#else
+ err = fsync_inode_buffers(inode);
+#endif
+
+ spin_lock(&inode_lock);
+ if (!(inode->i_state & I_DIRTY))
+ goto out;
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ goto out;
+ spin_unlock(&inode_lock);
+ write_inode_now(inode, 1);
+ return err;
+
+ out:
+ spin_unlock(&inode_lock);
+ return err;
+}
+
+/**
* clear_inode - clear an inode
* @inode: inode to clear
*
@@ -292,6 +354,9 @@ void write_inode_now(struct inode *inode, int sync)
void clear_inode(struct inode *inode)
{
+ if (!list_empty(&inode->i_dirty_buffers))
+ invalidate_inode_buffers(inode);
+
if (inode->i_data.nrpages)
BUG();
if (!(inode->i_state & I_FREEING))
@@ -351,6 +416,7 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru
inode = list_entry(tmp, struct inode, i_list);
if (inode->i_sb != sb)
continue;
+ invalidate_inode_buffers(inode);
if (!atomic_read(&inode->i_count)) {
list_del(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_hash);
@@ -412,7 +478,8 @@ int invalidate_inodes(struct super_block * sb)
* dispose_list.
*/
#define CAN_UNUSE(inode) \
- (((inode)->i_state | (inode)->i_data.nrpages) == 0)
+ ((((inode)->i_state | (inode)->i_data.nrpages) == 0) && \
+ !inode_has_buffers(inode))
#define INODE(entry) (list_entry(entry, struct inode, i_list))
void prune_icache(int goal)
@@ -911,7 +978,7 @@ void update_atime (struct inode *inode)
if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
if ( IS_RDONLY (inode) ) return;
inode->i_atime = CURRENT_TIME;
- mark_inode_dirty (inode);
+ mark_inode_dirty_sync (inode);
} /* End Function update_atime */
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index c9915cf80..6f0957dce 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -115,9 +115,6 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
char *p = NULL; /* Quiet GCC */
struct iso_directory_record *de;
- if (filp->f_pos >= inode->i_size)
- return 0;
-
offset = filp->f_pos & (bufsize - 1);
block = filp->f_pos >> bufbits;
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
@@ -132,7 +129,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
}
de = (struct iso_directory_record *) (bh->b_data + offset);
- if (first_de) inode_number = (bh->b_blocknr << bufbits) + offset;
+ if (first_de)
+ inode_number = (bh->b_blocknr << bufbits) + offset;
de_len = *(unsigned char *) de;
@@ -165,7 +163,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
return 0;
memcpy((void *) tmpde + slop, bh->b_data, offset);
}
- de = tmpde;
+ de = tmpde;
}
if (de->flags[-high_sierra] & 0x80) {
@@ -207,7 +205,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
map = 1;
if (inode->i_sb->u.isofs_sb.s_rock) {
len = get_rock_ridge_filename(de, tmpname, inode);
- if (len != 0) {
+ if (len != 0) { /* may be -1 */
p = tmpname;
map = 0;
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 453e4a456..5d50c37a6 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -45,14 +45,14 @@ static int check_bread = 0;
static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
static int isofs_hash(struct dentry *parent, struct qstr *qstr);
-static int isofs_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
-static int isofs_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
#ifdef CONFIG_JOLIET
static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr);
static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr);
-static int isofs_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
-static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
#endif
static void isofs_put_super(struct super_block *sb)
@@ -84,20 +84,20 @@ static struct super_operations isofs_sops = {
static struct dentry_operations isofs_dentry_ops[] = {
{
d_hash: isofs_hash,
- d_compare: isofs_cmp,
+ d_compare: isofs_dentry_cmp,
},
{
d_hash: isofs_hashi,
- d_compare: isofs_cmpi,
+ d_compare: isofs_dentry_cmpi,
},
#ifdef CONFIG_JOLIET
{
d_hash: isofs_hash_ms,
- d_compare: isofs_cmp_ms,
+ d_compare: isofs_dentry_cmp_ms,
},
{
d_hash: isofs_hashi_ms,
- d_compare: isofs_cmpi_ms,
+ d_compare: isofs_dentry_cmpi_ms,
}
#endif
};
@@ -173,7 +173,7 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
* Case insensitive compare of two isofs names.
*/
static int
-isofs_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
+isofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
{
int alen, blen;
@@ -197,7 +197,7 @@ isofs_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
* Case sensitive compare of two isofs names.
*/
static int
-isofs_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
+isofs_dentry_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
{
int alen, blen;
@@ -230,15 +230,15 @@ isofs_hashi(struct dentry *dentry, struct qstr *qstr)
}
static int
-isofs_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b)
+isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b)
{
- return isofs_cmp_common(dentry, a, b, 0);
+ return isofs_dentry_cmp_common(dentry, a, b, 0);
}
static int
-isofs_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b)
+isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b)
{
- return isofs_cmpi_common(dentry, a, b, 0);
+ return isofs_dentry_cmpi_common(dentry, a, b, 0);
}
#ifdef CONFIG_JOLIET
@@ -255,15 +255,15 @@ isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
}
static int
-isofs_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
+isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
{
- return isofs_cmp_common(dentry, a, b, 1);
+ return isofs_dentry_cmp_common(dentry, a, b, 1);
}
static int
-isofs_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
+isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
{
- return isofs_cmpi_common(dentry, a, b, 1);
+ return isofs_dentry_cmpi_common(dentry, a, b, 1);
}
#endif
@@ -500,15 +500,13 @@ static struct super_block *isofs_read_super(struct super_block *s, void *data,
* that value.
*/
blocksize = get_hardblocksize(dev);
- if( (blocksize != 0)
- && (blocksize > opt.blocksize) )
- {
+ if(blocksize > opt.blocksize) {
/*
* Force the blocksize we are going to use to be the
* hardware blocksize.
*/
opt.blocksize = blocksize;
- }
+ }
blocksize_bits = 0;
{
@@ -605,9 +603,8 @@ static struct super_block *isofs_read_super(struct super_block *s, void *data,
pri_bh = NULL;
root_found:
- brelse(pri_bh);
- if (joliet_level && opt.rock == 'n') {
+ if (joliet_level && (pri == NULL || opt.rock == 'n')) {
/* This is the case of Joliet with the norock mount flag.
* A disc with both Joliet and Rock Ridge is handled later
*/
@@ -704,6 +701,7 @@ root_found:
* We're all done using the volume descriptor, and may need
* to change the device blocksize, so release the buffer now.
*/
+ brelse(pri_bh);
brelse(bh);
/*
@@ -756,8 +754,9 @@ root_found:
s->u.isofs_sb.s_gid = opt.gid;
s->u.isofs_sb.s_utf8 = opt.utf8;
/*
- * It would be incredibly stupid to allow people to mark every file on the disk
- * as suid, so we merely allow them to set the default permissions.
+ * It would be incredibly stupid to allow people to mark every file
+ * on the disk as suid, so we merely allow them to set the default
+ * permissions.
*/
s->u.isofs_sb.s_mode = opt.mode & 0777;
@@ -873,7 +872,7 @@ static int isofs_statfs (struct super_block *sb, struct statfs *buf)
/* Life is simpler than for other filesystem since we never
* have to create a new block, only find an existing one.
*/
-int isofs_get_block(struct inode *inode, long iblock,
+static int isofs_get_block(struct inode *inode, long iblock,
struct buffer_head *bh_result, int create)
{
unsigned long b_off;
@@ -940,26 +939,26 @@ abort:
return err;
abort_create_attempted:
- printk("_isofs_bmap: Kernel tries to allocate a block\n");
+ printk("isofs_get_block: Kernel tries to allocate a block\n");
goto abort;
abort_negative:
- printk("_isofs_bmap: block < 0\n");
+ printk("isofs_get_block: block < 0\n");
goto abort;
abort_beyond_end:
- printk("_isofs_bmap: block >= EOF (%ld, %ld)\n",
+ printk("isofs_get_block: block >= EOF (%ld, %ld)\n",
iblock, (unsigned long) inode->i_size);
goto abort;
abort_too_many_sections:
- printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
- printk("isofs_bmap: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n",
+ printk("isofs_get_block: More than 100 file sections ?!?, aborting...\n");
+ printk("isofs_get_block: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n",
inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino);
goto abort;
}
-int isofs_bmap(struct inode *inode, int block)
+static int isofs_bmap(struct inode *inode, int block)
{
struct buffer_head dummy;
int error;
@@ -1019,10 +1018,7 @@ static int isofs_read_level3_size(struct inode * inode)
unsigned long block, offset;
int i = 0;
int more_entries = 0;
- struct iso_directory_record * tmpde = kmalloc(256, GFP_KERNEL);
-
- if (!tmpde)
- return -ENOMEM;
+ struct iso_directory_record * tmpde = NULL;
inode->i_size = 0;
inode->u.isofs_i.i_next_section_ino = 0;
@@ -1056,6 +1052,11 @@ static int isofs_read_level3_size(struct inode * inode)
/* Make sure we have a full directory entry */
if (offset >= bufsize) {
int slop = bufsize - offset + de_len;
+ if (!tmpde) {
+ tmpde = kmalloc(256, GFP_KERNEL);
+ if (!tmpde)
+ goto out_nomem;
+ }
memcpy(tmpde, de, slop);
offset &= bufsize - 1;
block++;
@@ -1082,14 +1083,23 @@ static int isofs_read_level3_size(struct inode * inode)
goto out_toomany;
} while(more_entries);
out:
- kfree(tmpde);
- if (bh) brelse(bh);
+ if (tmpde)
+ kfree(tmpde);
+ if (bh)
+ brelse(bh);
return 0;
+out_nomem:
+ if (bh)
+ brelse(bh);
+ return -ENOMEM;
+
out_noread:
printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
- kfree(tmpde);
- return 1;
+ if (tmpde)
+ kfree(tmpde);
+ return -EIO;
+
out_toomany:
printk(KERN_INFO "isofs_read_level3_size: "
"More than 100 file sections ?!?, aborting...\n"
@@ -1104,22 +1114,39 @@ static void isofs_read_inode(struct inode * inode)
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
int high_sierra = sb->u.isofs_sb.s_high_sierra;
- struct buffer_head * bh;
- struct iso_directory_record * raw_inode;
- unsigned char *pnt;
+ struct buffer_head * bh = NULL;
+ struct iso_directory_record * de;
+ struct iso_directory_record * tmpde = NULL;
+ unsigned int de_len;
+ unsigned long offset;
int volume_seq_no, i;
bh = bread(inode->i_dev, block, bufsize);
- if (!bh) {
- printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
- goto fail;
- }
+ if (!bh)
+ goto out_badread;
+
+ offset = (inode->i_ino & (bufsize - 1));
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ de_len = *(unsigned char *) de;
+
+ if (offset + de_len > bufsize) {
+ int frag1 = bufsize - offset;
- pnt = ((unsigned char *) bh->b_data
- + (inode->i_ino & (bufsize - 1)));
- raw_inode = ((struct iso_directory_record *) pnt);
+ tmpde = kmalloc(de_len, GFP_KERNEL);
+ if (tmpde == NULL) {
+ printk(KERN_INFO "isofs_read_inode: out of memory\n");
+ goto fail;
+ }
+ memcpy(tmpde, bh->b_data + offset, frag1);
+ brelse(bh);
+ bh = bread(inode->i_dev, ++block, bufsize);
+ if (!bh)
+ goto out_badread;
+ memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1);
+ de = tmpde;
+ }
- if (raw_inode->flags[-high_sierra] & 2) {
+ if (de->flags[-high_sierra] & 2) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
inode->i_nlink = 1; /* Set to 1. We know there are 2, but
the find utility tries to optimize
@@ -1134,10 +1161,10 @@ static void isofs_read_inode(struct inode * inode)
/* If there are no periods in the name,
* then set the execute permission bit
*/
- for(i=0; i< raw_inode->name_len[0]; i++)
- if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
+ for(i=0; i< de->name_len[0]; i++)
+ if(de->name[i]=='.' || de->name[i]==';')
break;
- if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';')
+ if(i == de->name_len[0] || de->name[i] == ';')
inode->i_mode |= S_IXUGO; /* execute permission */
}
inode->i_uid = inode->i_sb->u.isofs_sb.s_uid;
@@ -1145,84 +1172,77 @@ static void isofs_read_inode(struct inode * inode)
inode->i_blocks = inode->i_blksize = 0;
- inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size);
- if(raw_inode->flags[-high_sierra] & 0x80) {
+ inode->u.isofs_i.i_section_size = isonum_733 (de->size);
+ if(de->flags[-high_sierra] & 0x80) {
if(isofs_read_level3_size(inode)) goto fail;
} else {
- inode->i_size = isonum_733 (raw_inode->size);
+ inode->i_size = isonum_733 (de->size);
}
/* There are defective discs out there - we do this to protect
ourselves. A cdrom will never contain more than 800Mb
.. but a DVD may be up to 1Gig (Ulrich Habel) */
- if((inode->i_size < 0 || inode->i_size > 1073741824) &&
+
+ if ((inode->i_size < 0 || inode->i_size > 1073741824) &&
inode->i_sb->u.isofs_sb.s_cruft == 'n') {
- printk(KERN_WARNING "Warning: defective CD-ROM. Enabling \"cruft\" mount option.\n");
- inode->i_sb->u.isofs_sb.s_cruft = 'y';
+ printk(KERN_WARNING "Warning: defective CD-ROM. "
+ "Enabling \"cruft\" mount option.\n");
+ inode->i_sb->u.isofs_sb.s_cruft = 'y';
}
-/* Some dipshit decided to store some other bit of information in the high
- byte of the file length. Catch this and holler. WARNING: this will make
- it impossible for a file to be > 16Mb on the CDROM!!!*/
+ /*
+ * Some dipshit decided to store some other bit of information
+ * in the high byte of the file length. Catch this and holler.
+ * WARNING: this will make it impossible for a file to be > 16MB
+ * on the CDROM.
+ */
- if(inode->i_sb->u.isofs_sb.s_cruft == 'y' &&
- inode->i_size & 0xff000000){
-/* printk("Illegal format on cdrom. Pester manufacturer.\n"); */
- inode->i_size &= 0x00ffffff;
+ if (inode->i_sb->u.isofs_sb.s_cruft == 'y' &&
+ inode->i_size & 0xff000000) {
+ inode->i_size &= 0x00ffffff;
}
- if (raw_inode->interleave[0]) {
+ if (de->interleave[0]) {
printk("Interleaved files not (yet) supported.\n");
inode->i_size = 0;
}
/* I have no idea what file_unit_size is used for, so
we will flag it for now */
- if(raw_inode->file_unit_size[0] != 0){
- printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino);
+ if (de->file_unit_size[0] != 0) {
+ printk("File unit size != 0 for ISO file (%ld).\n",
+ inode->i_ino);
}
/* I have no idea what other flag bits are used for, so
we will flag it for now */
#ifdef DEBUG
- if((raw_inode->flags[-high_sierra] & ~2)!= 0){
+ if((de->flags[-high_sierra] & ~2)!= 0){
printk("Unusual flag settings for ISO file (%ld %x).\n",
- inode->i_ino, raw_inode->flags[-high_sierra]);
+ inode->i_ino, de->flags[-high_sierra]);
}
#endif
-#ifdef DEBUG
- printk("Get inode %x: %d %d: %d\n",inode->i_ino, block,
- ((int)pnt) & 0x3ff, inode->i_size);
-#endif
-
inode->i_mtime = inode->i_atime = inode->i_ctime =
- iso_date(raw_inode->date, high_sierra);
+ iso_date(de->date, high_sierra);
- inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) +
- isonum_711 (raw_inode->ext_attr_length));
+ inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) +
+ isonum_711 (de->ext_attr_length));
-/* Now test for possible Rock Ridge extensions which will override some of
- these numbers in the inode structure. */
+ /*
+ * Now test for possible Rock Ridge extensions which will override
+ * some of these numbers in the inode structure.
+ */
if (!high_sierra) {
- parse_rock_ridge_inode(raw_inode, inode);
- /* hmm..if we want uid or gid set, override the rock ridge setting */
- test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
- test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid);
+ parse_rock_ridge_inode(de, inode);
+ /* if we want uid/gid set, override the rock ridge setting */
+ test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
+ test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid);
}
-#ifdef DEBUG
- printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
-#endif
-
/* get the volume sequence number */
- volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ;
-
- /*
- * All done with buffer ... no more references to buffer memory!
- */
- brelse(bh);
+ volume_seq_no = isonum_723 (de->volume_sequence_number) ;
/*
* Disable checking if we see any volume number other than 0 or 1.
@@ -1232,8 +1252,10 @@ static void isofs_read_inode(struct inode * inode)
*/
if (inode->i_sb->u.isofs_sb.s_cruft == 'n' &&
(volume_seq_no != 0) && (volume_seq_no != 1)) {
- printk(KERN_WARNING "Warning: defective CD-ROM (volume sequence number). Enabling \"cruft\" mount option.\n");
- inode->i_sb->u.isofs_sb.s_cruft = 'y';
+ printk(KERN_WARNING "Warning: defective CD-ROM "
+ "(volume sequence number %d). "
+ "Enabling \"cruft\" mount option.\n", volume_seq_no);
+ inode->i_sb->u.isofs_sb.s_cruft = 'y';
}
/* Install the inode operations vector */
@@ -1244,25 +1266,32 @@ static void isofs_read_inode(struct inode * inode)
} else
#endif IGNORE_WRONG_MULTI_VOLUME_SPECS
{
- if (S_ISREG(inode->i_mode)) {
- inode->i_fop = &generic_ro_fops;
- inode->i_data.a_ops = &isofs_aops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &isofs_dir_inode_operations;
- inode->i_fop = &isofs_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_data.a_ops = &isofs_symlink_aops;
- } else
- /* XXX - parse_rock_ridge_inode() had already set i_rdev. */
- init_special_inode(inode, inode->i_mode, kdev_t_to_nr(inode->i_rdev));
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_fop = &generic_ro_fops;
+ inode->i_data.a_ops = &isofs_aops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &isofs_dir_inode_operations;
+ inode->i_fop = &isofs_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &isofs_symlink_aops;
+ } else
+ /* XXX - parse_rock_ridge_inode() had already set i_rdev. */
+ init_special_inode(inode, inode->i_mode,
+ kdev_t_to_nr(inode->i_rdev));
}
+ out:
+ if (tmpde)
+ kfree(tmpde);
+ if (bh)
+ brelse(bh);
return;
- fail:
- /* With a data error we return this information */
+ out_badread:
+ printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
+ fail:
make_bad_inode(inode);
- return;
+ goto out;
}
#ifdef LEAK_CHECK
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 4473f7c0d..3f44d9033 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -53,9 +53,7 @@ isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
* isofs_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as an inode number). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
+ * returns the inode number of the found entry, or 0 on error.
*/
static unsigned long
isofs_find_entry(struct inode *dir, struct dentry *dentry,
@@ -123,7 +121,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
if (dir->i_sb->u.isofs_sb.s_rock &&
((i = get_rock_ridge_filename(de, tmpname, dir)))) {
- dlen = i;
+ dlen = i; /* possibly -1 */
dpnt = tmpname;
#ifdef CONFIG_JOLIET
} else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
@@ -142,8 +140,9 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
* Skip hidden or associated files unless unhide is set
*/
match = 0;
- if ((!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
- || dir->i_sb->u.isofs_sb.s_unhide == 'y') && dlen)
+ if (dlen > 0 &&
+ (!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
+ || dir->i_sb->u.isofs_sb.s_unhide == 'y'))
{
match = (isofs_cmp(dentry,dpnt,dlen) == 0);
}
@@ -162,13 +161,14 @@ struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry)
struct inode *inode;
struct page *page;
-#ifdef DEBUG
- printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
-#endif
dentry->d_op = dir->i_sb->s_root->d_op;
page = alloc_page(GFP_USER);
- ino = isofs_find_entry(dir, dentry, page_address(page), 1024 + page_address(page));
+ if (!page)
+ return ERR_PTR(-ENOMEM);
+
+ ino = isofs_find_entry(dir, dentry, page_address(page),
+ 1024 + page_address(page));
__free_page(page);
inode = NULL;
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index b2eff877f..4ac4bc0ce 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -72,7 +72,7 @@
cont_size = 0; \
cont_offset = 0; \
goto LABEL; \
- }; \
+ } \
printk("Unable to read rock-ridge attributes\n"); \
}}
@@ -120,22 +120,16 @@ int find_rock_ridge_relocation(struct iso_directory_record * de,
CHECK_SP(goto out);
break;
case SIG('C','L'):
-#ifdef DEBUG
- printk("RR: CL\n");
-#endif
if (flag == 0) {
retval = isonum_733(rr->u.CL.location);
goto out;
- };
+ }
break;
case SIG('P','L'):
-#ifdef DEBUG
- printk("RR: PL\n");
-#endif
if (flag != 0) {
retval = isonum_733(rr->u.PL.location);
goto out;
- };
+ }
break;
case SIG('C','E'):
CHECK_CE; /* This tells is if there is a continuation record */
@@ -143,8 +137,8 @@ int find_rock_ridge_relocation(struct iso_directory_record * de,
default:
break;
}
- };
- };
+ }
+ }
MAYBE_CONTINUE(repeat, inode);
return retval;
out:
@@ -152,6 +146,7 @@ int find_rock_ridge_relocation(struct iso_directory_record * de,
return retval;
}
+/* return length of name field; 0: not found, -1: to be ignored */
int get_rock_ridge_filename(struct iso_directory_record * de,
char * retname, struct inode * inode)
{
@@ -202,24 +197,21 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
if (rr->u.NM.flags & ~1) {
printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
break;
- };
+ }
if((strlen(retname) + rr->len - 5) >= 254) {
truncate = 1;
break;
- };
+ }
strncat(retname, rr->u.NM.name, rr->len - 5);
retnamlen += rr->len - 5;
break;
case SIG('R','E'):
-#ifdef DEBUG
- printk("RR: RE (%x)\n", inode->i_ino);
-#endif
if (buffer) kfree(buffer);
- return 0;
+ return -1;
default:
break;
}
- };
+ }
}
MAYBE_CONTINUE(repeat,inode);
return retnamlen; /* If 0, this file did not have a NM field */
@@ -265,10 +257,10 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
break;
case SIG('E','R'):
inode->i_sb->u.isofs_sb.s_rock = 1;
- printk(KERN_DEBUG"ISO 9660 Extensions: ");
+ printk(KERN_DEBUG "ISO 9660 Extensions: ");
{ int p;
for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
- };
+ }
printk("\n");
break;
case SIG('P','X'):
@@ -293,7 +285,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
} else {
inode->i_rdev = MKDEV(high, low);
}
- };
+ }
break;
case SIG('T','F'):
/* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
@@ -333,7 +325,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
break;
default:
printk("Symlink component flag not implemented\n");
- };
+ }
slen -= slp->len + 2;
oldslp = slp;
slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
@@ -347,19 +339,16 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
/*
* If this component record isn't continued, then append a '/'.
*/
- if( (!rootflag)
- && ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
+ if (!rootflag && (oldslp->flags & 1) == 0)
+ inode->i_size += 1;
}
}
symlink_len = inode->i_size;
break;
case SIG('R','E'):
- printk("Attempt to read inode for relocated directory\n");
+ printk(KERN_WARNING "Attempt to read inode for relocated directory\n");
goto out;
case SIG('C','L'):
-#ifdef DEBUG
- printk("RR CL (%x)\n",inode->i_ino);
-#endif
inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
reloc = iget(inode->i_sb,
(inode->u.isofs_i.i_first_extent <<
@@ -380,7 +369,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
default:
break;
}
- };
+ }
}
MAYBE_CONTINUE(repeat,inode);
return 0;
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index 12cd2d304..b966c512b 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -98,7 +98,7 @@ isonum_733 (char * p)
int iso_date(char * p, int flag)
{
- int year, month, day, hour ,minute, second, tz;
+ int year, month, day, hour, minute, second, tz;
int crtime, days, i;
year = p[0] - 70;
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 211b01530..592851be6 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -50,7 +50,7 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
nlmclnt_next_cookie(&argp->cookie);
argp->state = nsm_local_state;
- memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry), sizeof(struct nfs_fh));
+ memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
lock->caller = system_utsname.nodename;
lock->oh.data = req->a_owner;
lock->oh.len = sprintf(req->a_owner, "%d@%s",
diff --git a/fs/locks.c b/fs/locks.c
index 7da293a31..e65b59394 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -511,7 +511,8 @@ static inline void locks_unlock_delete(struct file_lock **thisfl_p)
struct file_lock *fl = *thisfl_p;
int (*lock)(struct file *, int, struct file_lock *);
- if ((lock = fl->fl_file->f_op->lock) != NULL) {
+ if (fl->fl_file->f_op &&
+ (lock = fl->fl_file->f_op->lock) != NULL) {
fl->fl_type = F_UNLCK;
lock(fl->fl_file, F_SETLK, fl);
}
@@ -1355,7 +1356,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
if (!flock_to_posix_lock(filp, &file_lock, &flock))
goto out_putf;
- if (filp->f_op->lock) {
+ if (filp->f_op && filp->f_op->lock) {
error = filp->f_op->lock(filp, F_GETLK, &file_lock);
if (error < 0)
goto out_putf;
@@ -1479,7 +1480,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
goto out_putf;
}
- if (filp->f_op->lock != NULL) {
+ if (filp->f_op && filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, file_lock);
if (error < 0)
goto out_putf;
@@ -1520,7 +1521,7 @@ int fcntl_getlk64(unsigned int fd, struct flock64 *l)
if (!flock64_to_posix_lock(filp, &file_lock, &flock))
goto out_putf;
- if (filp->f_op->lock) {
+ if (filp->f_op && filp->f_op->lock) {
error = filp->f_op->lock(filp, F_GETLK, &file_lock);
if (error < 0)
goto out_putf;
@@ -1617,12 +1618,12 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
goto out_putf;
}
- if (filp->f_op->lock != NULL) {
+ if (filp->f_op && filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, file_lock);
if (error < 0)
goto out_putf;
}
- error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);
+ error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64);
out_putf:
fput(filp);
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 38bb52cfd..7ff0b7bd9 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -396,7 +396,7 @@ struct buffer_head * minix_bread(struct inode * inode, int block, int create)
return NULL;
}
-static int minix_writepage(struct file *file, struct page *page)
+static int minix_writepage(struct page *page)
{
return block_write_full_page(page,minix_get_block);
}
diff --git a/fs/namei.c b/fs/namei.c
index c0d1abc36..37644f4a1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -152,18 +152,10 @@ char * getname(const char * filename)
* for filesystem access without changing the "normal" uids which
* are used for other things..
*/
-int permission(struct inode * inode,int mask)
+int vfs_permission(struct inode * inode,int mask)
{
int mode = inode->i_mode;
- if (inode->i_op && inode->i_op->permission) {
- int retval;
- lock_kernel();
- retval = inode->i_op->permission(inode, mask);
- unlock_kernel();
- return retval;
- }
-
if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
return -EROFS; /* Nobody gets write access to a read-only fs */
@@ -188,6 +180,18 @@ int permission(struct inode * inode,int mask)
return -EACCES;
}
+int permission(struct inode * inode,int mask)
+{
+ if (inode->i_op && inode->i_op->permission) {
+ int retval;
+ lock_kernel();
+ retval = inode->i_op->permission(inode, mask);
+ unlock_kernel();
+ return retval;
+ }
+ return vfs_permission(inode, mask);
+}
+
/*
* get_write_access() gets write permission for a file.
* put_write_access() releases this write permission.
diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in
index 104f5a3c7..1f1eb1278 100644
--- a/fs/ncpfs/Config.in
+++ b/fs/ncpfs/Config.in
@@ -7,7 +7,5 @@ dep_mbool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG $CONFI
dep_mbool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS $CONFIG_NCP_FS
dep_mbool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS $CONFIG_NCP_FS
dep_mbool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS $CONFIG_NCP_FS
-dep_mbool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR $CONFIG_NCP_FS
-dep_mbool ' NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS $CONFIG_NCP_FS
dep_mbool ' Use Native Language Support' CONFIG_NCPFS_NLS $CONFIG_NCP_FS
dep_mbool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS $CONFIG_NCP_FS
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 4b6afe2e9..37c87f8b2 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -165,7 +165,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
}
-#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
case NCP_IOC_GETROOT:
{
struct ncp_setroot_ioctl sr;
@@ -241,7 +240,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
}
-#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
#ifdef CONFIG_NCPFS_PACKET_SIGNING
case NCP_IOC_SIGN_INIT:
@@ -374,7 +372,6 @@ outrel:
}
#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
-#ifdef CONFIG_NCPFS_NDS_DOMAINS
case NCP_IOC_GETOBJECTNAME:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -503,7 +500,6 @@ outrel:
if (old) ncp_kfree_s(old, oldlen);
return 0;
}
-#endif /* CONFIG_NCPFS_NDS_DOMAINS */
#ifdef CONFIG_NCPFS_NLS
/* Here we are select the iocharset and the codepage for NLS.
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 6d07ead73..162c89b4b 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -96,16 +96,14 @@ ncp_ClearPhysicalRecord(struct ncp_server *server,
__u32 offset, __u32 length);
#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
-#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
int
ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *,
__u8, __u8, __u32);
-#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
#ifdef CONFIG_NCPFS_NLS
-inline unsigned char ncp__tolower(struct nls_table *, unsigned char);
-inline unsigned char ncp__toupper(struct nls_table *, unsigned char);
+unsigned char ncp__tolower(struct nls_table *, unsigned char);
+unsigned char ncp__toupper(struct nls_table *, unsigned char);
int ncp__io2vol(struct ncp_server *, unsigned char *, unsigned int *,
const unsigned char *, unsigned int, int);
int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c66d870d9..564a47b32 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -63,6 +63,7 @@ struct inode_operations nfs_dir_inode_operations = {
rmdir: nfs_rmdir,
mknod: nfs_mknod,
rename: nfs_rename,
+ permission: nfs_permission,
revalidate: nfs_revalidate,
setattr: nfs_notify_change,
};
@@ -97,6 +98,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
{
struct file *file = desc->file;
struct inode *inode = file->f_dentry->d_inode;
+ struct rpc_cred *cred = nfs_file_cred(file);
void *buffer = kmap(page);
int plus = NFS_USE_READDIRPLUS(inode);
int error;
@@ -104,7 +106,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
again:
- error = NFS_PROTO(inode)->readdir(file, desc->entry->cookie, buffer,
+ error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,
NFS_SERVER(inode)->dtsize, plus);
/* We requested READDIRPLUS, but the server doesn't grok it */
if (desc->plus && error == -ENOTSUPP) {
@@ -308,6 +310,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
{
struct file *file = desc->file;
struct inode *inode = file->f_dentry->d_inode;
+ struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
u32 *p;
int status = -EIO;
@@ -324,7 +327,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
goto out;
}
p = kmap(page);
- status = NFS_PROTO(inode)->readdir(file, desc->target, p,
+ status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p,
NFS_SERVER(inode)->dtsize, 0);
if (status >= 0) {
p = desc->decode(p, desc->entry, 0);
@@ -483,16 +486,15 @@ static inline int nfs_neg_need_reval(struct dentry *dentry)
*/
static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode;
- struct inode * inode = dentry->d_inode;
+ struct inode *dir;
+ struct inode *inode;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
lock_kernel();
- dir = dentry->d_parent;
- dir_i = dir->d_inode;
+ dir = dentry->d_parent->d_inode;
+ inode = dentry->d_inode;
/*
* If we don't have an inode, let's look at the parent
* directory mtime to get a hint about how often we
@@ -506,7 +508,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
if (is_bad_inode(inode)) {
dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
- dir->d_name.name, dentry->d_name.name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
goto out_bad;
}
@@ -514,15 +516,14 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
goto out_valid;
if (IS_ROOT(dentry)) {
- __nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ __nfs_revalidate_inode(NFS_SERVER(inode), inode);
goto out_valid_renew;
}
/*
* Do a new lookup and check the dentry attributes.
*/
- error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
- &fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -532,13 +533,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
- /* Filehandle matches? */
- if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
- goto out_bad;
-
- /* Ok, remeber that we successfully checked it.. */
+ /* Ok, remember that we successfully checked it.. */
nfs_refresh_inode(inode, &fattr);
+ if (nfs_inode_is_stale(inode, &fhandle, &fattr))
+ goto out_bad;
+
out_valid_renew:
nfs_renew_times(dentry);
out_valid:
@@ -551,7 +551,7 @@ out_bad:
goto out_valid;
d_drop(dentry);
/* Purge readdir caches. */
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
if (inode && S_ISDIR(inode->i_mode))
nfs_zap_caches(inode);
unlock_kernel();
@@ -575,30 +575,6 @@ static int nfs_dentry_delete(struct dentry *dentry)
}
-static kmem_cache_t *nfs_fh_cachep;
-
-__inline__ struct nfs_fh *nfs_fh_alloc(void)
-{
- return kmem_cache_alloc(nfs_fh_cachep, SLAB_KERNEL);
-}
-
-__inline__ void nfs_fh_free(struct nfs_fh *p)
-{
- kmem_cache_free(nfs_fh_cachep, p);
-}
-
-/*
- * Called when the dentry is being freed to release private memory.
- */
-static void nfs_dentry_release(struct dentry *dentry)
-{
- if (dentry->d_fsdata) {
- lock_kernel();
- nfs_fh_free(dentry->d_fsdata);
- unlock_kernel();
- }
-}
-
/*
* Called when the dentry loses inode.
* We use it to clean up silly-renamed files.
@@ -616,35 +592,27 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
struct dentry_operations nfs_dentry_operations = {
d_revalidate: nfs_lookup_revalidate,
d_delete: nfs_dentry_delete,
- d_release: nfs_dentry_release,
d_iput: nfs_dentry_iput,
};
-static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
{
- struct dentry *dir = dentry->d_parent;
struct inode *inode;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
dfprintk(VFS, "NFS: lookup(%s/%s)\n",
- dir->d_name.name, dentry->d_name.name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
+ if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
goto out;
error = -ENOMEM;
- if (!dentry->d_fsdata) {
- dentry->d_fsdata = nfs_fh_alloc();
- if (!dentry->d_fsdata)
- goto out;
- }
dentry->d_op = &nfs_dentry_operations;
- error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
- &fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
inode = NULL;
if (error == -ENOENT)
goto no_entry;
@@ -686,16 +654,15 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
* that the operation succeeded on the server, but an error in the
* reply path made it appear to have failed.
*/
-static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
@@ -706,8 +673,8 @@ static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
* select the appropriate create strategy. Currently open_namei
* does not pass the create flags.
*/
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->create(dir, &dentry->d_name,
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
&attr, 0, &fhandle, &fattr);
if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -719,22 +686,21 @@ static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
/*
* See comments for nfs_proc_create regarding failed operations.
*/
-static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->mknod(dir, &dentry->d_name, &attr, rdev,
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
&fhandle, &fattr);
if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -746,16 +712,15 @@ static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int r
/*
* See comments for nfs_proc_create regarding failed operations.
*/
-static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
@@ -769,8 +734,8 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
*/
d_drop(dentry);
#endif
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
&fattr);
if (!error && fhandle.size != 0)
error = nfs_instantiate(dentry, &fhandle, &fattr);
@@ -779,25 +744,23 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
return error;
}
-static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, dentry->d_name.name);
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
return error;
}
-static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
static unsigned int sillycounter;
- const int i_inosize = sizeof(dir_i->i_ino)*2;
+ const int i_inosize = sizeof(dir->i_ino)*2;
const int countersize = sizeof(sillycounter)*2;
const int slen = strlen(".nfs") + i_inosize + countersize;
char silly[slen+1];
@@ -848,10 +811,10 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
goto out;
} while(sdentry->d_inode != NULL); /* need negative lookup */
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
qsilly.name = silly;
qsilly.len = strlen(silly);
- error = NFS_PROTO(dir_i)->rename(dir, &dentry->d_name, dir, &qsilly);
+ error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
if (!error) {
nfs_renew_times(dentry);
d_move(dentry, sdentry);
@@ -872,8 +835,7 @@ out:
*/
static int nfs_safe_remove(struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode;
+ struct inode *dir = dentry->d_parent->d_inode;
struct inode *inode = dentry->d_inode;
int error = -EBUSY, rehash = 0;
@@ -902,10 +864,10 @@ static int nfs_safe_remove(struct dentry *dentry)
goto out_delete;
}
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
if (inode)
NFS_CACHEINV(inode);
- error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
+ error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
if (error < 0)
goto out;
@@ -943,9 +905,8 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
}
static int
-nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- struct dentry *dir = dentry->d_parent;
struct iattr attr;
struct nfs_fattr sym_attr;
struct nfs_fh sym_fh;
@@ -954,10 +915,10 @@ nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
- dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
+ dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
error = -ENAMETOOLONG;
- maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+ maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
if (strlen(symname) > maxlen)
goto out;
@@ -976,15 +937,15 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
qsymname.name = symname;
qsymname.len = strlen(symname);
- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->symlink(dir, &dentry->d_name, &qsymname,
+ nfs_zap_caches(dir);
+ error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
&attr, &sym_fh, &sym_attr);
if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
} else {
if (error == -EEXIST)
printk("nfs_proc_symlink: %s/%s already exists??\n",
- dir->d_name.name, dentry->d_name.name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
d_drop(dentry);
}
@@ -993,9 +954,8 @@ out:
}
static int
-nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
struct inode *inode = old_dentry->d_inode;
int error;
@@ -1009,9 +969,9 @@ nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
* we can't use the existing dentry.
*/
d_drop(dentry);
- nfs_zap_caches(dir_i);
+ nfs_zap_caches(dir);
NFS_CACHEINV(inode);
- error = NFS_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name);
+ error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
return error;
}
@@ -1116,10 +1076,8 @@ go_ahead:
nfs_zap_caches(new_dir);
nfs_zap_caches(old_dir);
- error = NFS_PROTO(old_dir)->rename(old_dentry->d_parent,
- &old_dentry->d_name,
- new_dentry->d_parent,
- &new_dentry->d_name);
+ error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
+ new_dir, &new_dentry->d_name);
out:
if (rehash)
d_rehash(rehash);
@@ -1132,22 +1090,33 @@ out:
return error;
}
-int nfs_init_fhcache(void)
+int
+nfs_permission(struct inode *inode, int mask)
{
- nfs_fh_cachep = kmem_cache_create("nfs_fh",
- sizeof(struct nfs_fh),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (nfs_fh_cachep == NULL)
- return -ENOMEM;
+ int error = vfs_permission(inode, mask);
- return 0;
-}
+ if (!NFS_PROTO(inode)->access)
+ goto out;
+ /*
+ * Trust UNIX mode bits except:
+ *
+ * 1) When override capabilities may have been invoked
+ * 2) When root squashing may be involved
+ * 3) When ACLs may overturn a negative answer */
+ if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH)
+ && (current->fsuid != 0) && (current->fsgid != 0)
+ && error != -EACCES)
+ goto out;
-void nfs_destroy_fhcache(void)
-{
- if (kmem_cache_destroy(nfs_fh_cachep))
- printk(KERN_INFO "nfs_fh: not all structures were freed\n");
+ error = NFS_PROTO(inode)->access(inode, mask, 0);
+
+ if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv &&
+ current->uid != 0 && current->gid != 0 &&
+ (current->fsuid != current->uid || current->fsgid != current->gid))
+ error = NFS_PROTO(inode)->access(inode, mask, 1);
+
+ out:
+ return error;
}
/*
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index c30fc5062..d5c92ba3b 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -52,6 +52,7 @@ struct file_operations nfs_file_operations = {
};
struct inode_operations nfs_file_inode_operations = {
+ permission: nfs_permission,
revalidate: nfs_revalidate,
setattr: nfs_notify_change,
};
@@ -90,13 +91,14 @@ static ssize_t
nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
struct dentry * dentry = file->f_dentry;
+ struct inode * inode = dentry->d_inode;
ssize_t result;
dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long) *ppos);
- result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (!result)
result = generic_file_read(file, buf, count, ppos);
return result;
@@ -106,12 +108,13 @@ static int
nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
{
struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
int status;
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- status = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (!status)
status = generic_file_mmap(file, vma);
return status;
@@ -179,7 +182,7 @@ static int nfs_sync_page(struct page *page)
struct address_space *mapping;
struct inode *inode;
unsigned long index = page_index(page);
- unsigned int rpages, wpages;
+ unsigned int rpages;
int result;
mapping = page->mapping;
@@ -192,14 +195,8 @@ static int nfs_sync_page(struct page *page)
rpages = NFS_SERVER(inode)->rpages;
result = nfs_pagein_inode(inode, index, rpages);
if (result < 0)
- goto out_bad;
- wpages = NFS_SERVER(inode)->wpages;
- result = nfs_sync_file(inode, NULL, index, wpages, FLUSH_STABLE);
- if (result < 0)
- goto out_bad;
+ return result;
return 0;
- out_bad:
- return result;
}
struct address_space_operations nfs_file_aops = {
@@ -227,7 +224,7 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
result = -EBUSY;
if (IS_SWAPFILE(inode))
goto out_swapfile;
- result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (result)
goto out;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5b582024e..f741cb6dd 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -39,7 +39,7 @@
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
-static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *);
void nfs_zap_caches(struct inode *);
static void nfs_invalidate_inode(struct inode *);
@@ -222,13 +222,10 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
return NULL;
}
- inode = __nfs_fhget(sb, &fattr);
+ inode = __nfs_fhget(sb, rootfh, &fattr);
return inode;
}
-extern struct nfs_fh *nfs_fh_alloc(void);
-extern void nfs_fh_free(struct nfs_fh *p);
-
/*
* The way this works is that the mount process passes a structure
* in the data argument which contains the server's IP address
@@ -242,7 +239,7 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
struct nfs_server *server;
struct rpc_xprt *xprt = NULL;
struct rpc_clnt *clnt = NULL;
- struct nfs_fh *root = &data->root, *root_fh, fh;
+ struct nfs_fh *root = &data->root, fh;
struct inode *root_inode = NULL;
unsigned int authflavor;
struct sockaddr_in srvaddr;
@@ -365,16 +362,10 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
* Keep the super block locked while we try to get
* the root fh attributes.
*/
- root_fh = nfs_fh_alloc();
- if (!root_fh)
- goto out_no_fh;
- memcpy((u8*)root_fh, (u8*)root, sizeof(*root));
-
/* Did getting the root inode fail? */
if (!(root_inode = nfs_get_root(sb, root))
&& (data->flags & NFS_MOUNT_VER3)) {
data->flags &= ~NFS_MOUNT_VER3;
- nfs_fh_free(root_fh);
rpciod_down();
rpc_shutdown_client(server->client);
goto nfsv3_try_again;
@@ -387,7 +378,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
goto out_no_root;
sb->s_root->d_op = &nfs_dentry_operations;
- sb->s_root->d_fsdata = root_fh;
/* Get some general file system info */
if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
@@ -462,8 +452,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
out_no_root:
printk("nfs_read_super: get root inode failed\n");
iput(root_inode);
- nfs_fh_free(root_fh);
-out_no_fh:
rpciod_down();
goto out_shutdown;
@@ -507,7 +495,7 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
struct nfs_fsinfo res;
int error;
- error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
+ error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
buf->f_type = NFS_SUPER_MAGIC;
if (error < 0)
goto out_err;
@@ -532,43 +520,6 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
}
/*
- * Free all unused dentries in an inode's alias list.
- *
- * Subtle note: we have to be very careful not to cause
- * any IO operations with the stale dentries, as this
- * could cause file corruption. But since the dentry
- * count is 0 and all pending IO for a dentry has been
- * flushed when the count went to 0, we're safe here.
- * Also returns the number of unhashed dentries
- */
-static int
-nfs_free_dentries(struct inode *inode)
-{
- struct list_head *tmp, *head;
- int unhashed;
-
- if (S_ISDIR(inode->i_mode)) {
- struct dentry *dentry = d_find_alias(inode);
- if (dentry) {
- shrink_dcache_parent(dentry);
- dput(dentry);
- }
- }
- d_prune_aliases(inode);
- spin_lock(&dcache_lock);
- head = &inode->i_dentry;
- tmp = head;
- unhashed = 0;
- while ((tmp = tmp->next) != head) {
- struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
- if (list_empty(&dentry->d_hash))
- unhashed++;
- }
- spin_unlock(&dcache_lock);
- return unhashed;
-}
-
-/*
* Invalidate the local caches
*/
void
@@ -600,7 +551,7 @@ nfs_invalidate_inode(struct inode *inode)
* Fill in inode information from the fattr.
*/
static void
-nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
+nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
/*
* Check whether the mode has been set, as we only want to
@@ -638,10 +589,16 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
NFS_CACHE_ISIZE(inode) = fattr->size;
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+ memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
}
nfs_refresh_inode(inode, fattr);
}
+struct nfs_find_desc {
+ struct nfs_fh *fh;
+ struct nfs_fattr *fattr;
+};
+
/*
* In NFSv3 we can have 64bit inode numbers. In order to support
* this, and re-exported directories (also seen in NFSv2)
@@ -651,43 +608,38 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
static int
nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
{
- struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+ struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque;
+ struct nfs_fh *fh = desc->fh;
+ struct nfs_fattr *fattr = desc->fattr;
+
if (NFS_FSID(inode) != fattr->fsid)
return 0;
if (NFS_FILEID(inode) != fattr->fileid)
return 0;
+ if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
+ return 0;
return 1;
}
-static int
-nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
- int unhashed;
- int is_stale = 0;
+ /* Empty inodes are not stale */
+ if (!inode->i_mode)
+ return 0;
- if (inode->i_mode &&
- (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
- is_stale = 1;
+ if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+ return 1;
if (is_bad_inode(inode))
- is_stale = 1;
+ return 1;
- /*
- * If the inode seems stale, free up cached dentries.
- */
- unhashed = nfs_free_dentries(inode);
-
- /* Assume we're holding an i_count
- *
- * NB: sockets sometimes have volatile file handles
- * don't invalidate their inodes even if all dentries are
- * unhashed.
- */
- if (unhashed && atomic_read(&inode->i_count) == unhashed + 1
- && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
- is_stale = 1;
+ /* Has the filehandle changed? If so is the old one stale? */
+ if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
+ __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
+ return 1;
- return is_stale;
+ return 0;
}
/*
@@ -696,8 +648,6 @@ nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
* the vfs read_inode function because there is no way to pass the
* file handle or current attributes into the read_inode function.
*
- * We provide a special check for NetApp .snapshot directories to avoid
- * inode aliasing problems. All snapshot inodes are anonymous (unhashed).
*/
struct inode *
nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
@@ -708,44 +658,16 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(long long)fattr->fileid);
-
- /* Install the file handle in the dentry */
- memcpy(dentry->d_fsdata, fhandle, sizeof(struct nfs_fh));
-
-#ifdef CONFIG_NFS_SNAPSHOT
- /*
- * Check for NetApp snapshot dentries, and get an
- * unhashed inode to avoid aliasing problems.
- */
- if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
- (dentry->d_name.len == 9 &&
- memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
- struct inode *inode = new_inode(sb);
- if (!inode)
- goto out;
- inode->i_ino = nfs_fattr_to_ino_t(fattr);
- nfs_read_inode(inode);
- nfs_fill_inode(inode, fattr);
- inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
- dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
- out:
- return inode;
- }
-#endif
- return __nfs_fhget(sb, fattr);
+ return __nfs_fhget(sb, fhandle, fattr);
}
/*
* Look up the inode by super block and fattr->fileid.
- *
- * Note carefully the special handling of busy inodes (i_count > 1).
- * With the kernel 2.1.xx dcache all inodes except hard links must
- * have i_count == 1 after iget(). Otherwise, it indicates that the
- * server has reused a fileid (i_ino) and we have a stale inode.
*/
static struct inode *
-__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
+__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
+ struct nfs_find_desc desc = { fh, fattr };
struct inode *inode = NULL;
unsigned long ino;
@@ -759,33 +681,13 @@ __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
ino = nfs_fattr_to_ino_t(fattr);
- while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
-
- /*
- * Check for busy inodes, and attempt to get rid of any
- * unused local references. If successful, we release the
- * inode and try again.
- *
- * Note that the busy test uses the values in the fattr,
- * as the inode may have become a different object.
- * (We can probably handle modes changes here, too.)
- */
- if (!nfs_inode_is_stale(inode,fattr))
- break;
-
- dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
- inode->i_ino, atomic_read(&inode->i_count));
- nfs_zap_caches(inode);
- remove_inode_hash(inode);
- iput(inode);
- }
-
- if (!inode)
+ if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
goto out_no_inode;
- nfs_fill_inode(inode, fattr);
- dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino, atomic_read(&inode->i_count));
+ nfs_fill_inode(inode, fh, fattr);
+ dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
+ inode->i_dev, (long long)NFS_FILEID(inode),
+ atomic_read(&inode->i_count));
out:
return inode;
@@ -820,7 +722,7 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
if (error)
goto out;
- error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
+ error = NFS_PROTO(inode)->setattr(inode, &fattr, attr);
if (error)
goto out;
/*
@@ -872,7 +774,8 @@ nfs_wait_on_inode(struct inode *inode, int flag)
int
nfs_revalidate(struct dentry *dentry)
{
- return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ struct inode *inode = dentry->d_inode;
+ return nfs_revalidate_inode(NFS_SERVER(inode), inode);
}
/*
@@ -913,18 +816,16 @@ int nfs_release(struct inode *inode, struct file *filp)
* the cached attributes have to be refreshed.
*/
int
-__nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
- struct inode *inode = dentry->d_inode;
int status = 0;
struct nfs_fattr fattr;
- dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- inode->i_ino);
+ dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
+ inode->i_dev, (long long)NFS_FILEID(inode));
lock_kernel();
- if (!inode || is_bad_inode(inode)) {
+ if (!inode || is_bad_inode(inode) || NFS_STALE(inode)) {
unlock_kernel();
return -ESTALE;
}
@@ -936,55 +837,35 @@ __nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
return status;
}
if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
- unlock_kernel();
- return 0;
+ status = NFS_STALE(inode) ? -ESTALE : 0;
+ goto out_nowait;
}
}
NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
- status = NFS_PROTO(inode)->getattr(dentry, &fattr);
+ status = NFS_PROTO(inode)->getattr(inode, &fattr);
if (status) {
- struct dentry *dir = dentry->d_parent;
- struct inode *dir_i = dir->d_inode;
- int error;
- u32 *fh;
- struct nfs_fh fhandle;
- dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
- dir->d_name.name, dentry->d_name.name,
- inode->i_ino, status);
- if (status != -ESTALE)
- goto out;
- /*
- * A "stale filehandle" error ... show the current fh
- * and find out what the filehandle should be.
- */
- fh = (u32 *) NFS_FH(dentry)->data;
- dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
- fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
- error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name,
- &fhandle, &fattr);
- if (error) {
- dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
- goto out;
+ dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
+ inode->i_dev, (long long)NFS_FILEID(inode), status);
+ if (status == -ESTALE) {
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
+ remove_inode_hash(inode);
}
- fh = (u32 *) fhandle.data;
- dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n",
- fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
goto out;
}
status = nfs_refresh_inode(inode, &fattr);
if (status) {
- dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, inode->i_ino, status);
+ dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
+ inode->i_dev, (long long)NFS_FILEID(inode), status);
goto out;
}
- dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
+ inode->i_dev, (long long)NFS_FILEID(inode));
out:
NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
wake_up(&inode->i_wait);
+ out_nowait:
unlock_kernel();
return status;
}
@@ -1165,8 +1046,6 @@ out_changed:
*/
static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME);
-extern int nfs_init_fhcache(void);
-extern void nfs_destroy_fhcache(void);
extern int nfs_init_nfspagecache(void);
extern void nfs_destroy_nfspagecache(void);
extern int nfs_init_readpagecache(void);
@@ -1180,10 +1059,6 @@ init_nfs_fs(void)
{
int err;
- err = nfs_init_fhcache();
- if (err)
- return err;
-
err = nfs_init_nfspagecache();
if (err)
return err;
@@ -1218,7 +1093,6 @@ cleanup_module(void)
{
nfs_destroy_readpagecache();
nfs_destroy_nfspagecache();
- nfs_destroy_fhcache();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index d75e9eda0..86cfd1b81 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -37,34 +37,34 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* One function for each procedure in the NFS protocol.
*/
static int
-nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+nfs3_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
{
int status;
dprintk("NFS call getattr\n");
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR,
- NFS_FH(dentry), fattr, 0);
+ status = rpc_call(NFS_CLIENT(inode), NFS3PROC_GETATTR,
+ NFS_FH(inode), fattr, 0);
dprintk("NFS reply getattr\n");
return status;
}
static int
-nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+nfs3_proc_setattr(struct inode *inode, struct nfs_fattr *fattr,
struct iattr *sattr)
{
- struct nfs3_sattrargs arg = { NFS_FH(dentry), sattr, 0, 0 };
+ struct nfs3_sattrargs arg = { NFS_FH(inode), sattr, 0, 0 };
int status;
dprintk("NFS call setattr\n");
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0);
+ status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0);
dprintk("NFS reply setattr\n");
return status;
}
static int
-nfs3_proc_lookup(struct dentry *dir, struct qstr *name,
+nfs3_proc_lookup(struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_fattr dir_attr;
@@ -75,20 +75,20 @@ nfs3_proc_lookup(struct dentry *dir, struct qstr *name,
dprintk("NFS call lookup %s\n", name->name);
dir_attr.valid = 0;
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0);
if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR,
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR,
fhandle, fattr, 0);
dprintk("NFS reply lookup: %d\n", status);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ nfs_refresh_inode(dir, &dir_attr);
return status;
}
static int
-nfs3_proc_access(struct dentry *dentry, int mode, int ruid)
+nfs3_proc_access(struct inode *inode, int mode, int ruid)
{
struct nfs_fattr fattr;
- struct nfs3_accessargs arg = { NFS_FH(dentry), 0 };
+ struct nfs3_accessargs arg = { NFS_FH(inode), 0 };
struct nfs3_accessres res = { &fattr, 0 };
int status, flags;
@@ -97,7 +97,7 @@ nfs3_proc_access(struct dentry *dentry, int mode, int ruid)
if (mode & MAY_READ)
arg.access |= NFS3_ACCESS_READ;
- if (S_ISDIR(dentry->d_inode->i_mode)) {
+ if (S_ISDIR(inode->i_mode)) {
if (mode & MAY_WRITE)
arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
if (mode & MAY_EXEC)
@@ -109,8 +109,8 @@ nfs3_proc_access(struct dentry *dentry, int mode, int ruid)
arg.access |= NFS3_ACCESS_EXECUTE;
}
flags = (ruid) ? RPC_CALL_REALUID : 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags);
- nfs_refresh_inode(dentry->d_inode, &fattr);
+ status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags);
+ nfs_refresh_inode(inode, &fattr);
dprintk("NFS reply access\n");
if (status == 0 && (arg.access & res.access) != arg.access)
@@ -119,29 +119,28 @@ nfs3_proc_access(struct dentry *dentry, int mode, int ruid)
}
static int
-nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen)
+nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen)
{
struct nfs_fattr fattr;
- struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen };
+ struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen };
struct nfs3_readlinkres res = { &fattr, buffer, buflen };
int status;
dprintk("NFS call readlink\n");
fattr.valid = 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK,
+ status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
&args, &res, 0);
- nfs_refresh_inode(dentry->d_inode, &fattr);
+ nfs_refresh_inode(inode, &fattr);
dprintk("NFS reply readlink: %d\n", status);
return status;
}
static int
-nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
+nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, int flags,
loff_t offset, unsigned int count, void *buffer, int *eofp)
{
- struct dentry *dentry = file->f_dentry;
- struct rpc_cred *cred = nfs_file_cred(file);
- struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1,
+ struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1,
{{buffer, count}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}} };
struct nfs_readres res = { fattr, count, 0 };
@@ -150,20 +149,19 @@ nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
dprintk("NFS call read %d @ %Ld\n", count, (long long)offset);
fattr->valid = 0;
- status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+ status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
dprintk("NFS reply read: %d\n", status);
*eofp = res.eof;
return status;
}
static int
-nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags,
+nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, int flags,
loff_t offset, unsigned int count,
void *buffer, struct nfs_writeverf *verf)
{
- struct dentry *dentry = file->f_dentry;
- struct rpc_cred *cred = nfs_file_cred(file);
- struct nfs_writeargs arg = { NFS_FH(dentry), offset, count,
+ struct nfs_writeargs arg = { NFS_FH(inode), offset, count,
NFS_FILE_SYNC, 1,
{{buffer, count}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}} };
@@ -177,7 +175,7 @@ nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags,
rpcflags |= NFS_RPC_SWAPFLAGS;
arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
- status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags);
+ status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
dprintk("NFS reply read: %d\n", status);
return status < 0? status : res.count;
@@ -188,7 +186,7 @@ nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags,
* For now, we don't implement O_EXCL.
*/
static int
-nfs3_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+nfs3_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_fattr dir_attr;
@@ -208,8 +206,8 @@ nfs3_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
again:
dir_attr.valid = 0;
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0);
+ nfs_refresh_inode(dir, &dir_attr);
/* If the server doesn't support the exclusive creation semantics,
* try again with simple 'guarded' mode. */
@@ -242,7 +240,7 @@ exit:
* not sure this buys us anything (and I'd have
* to revamp the NFSv3 XDR code) */
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR,
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR,
&arg, fattr, 0);
dprintk("NFS reply setattr (post-create): %d\n", status);
}
@@ -251,7 +249,7 @@ exit:
}
static int
-nfs3_proc_remove(struct dentry *dir, struct qstr *name)
+nfs3_proc_remove(struct inode *dir, struct qstr *name)
{
struct nfs_fattr dir_attr;
struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len };
@@ -260,8 +258,8 @@ nfs3_proc_remove(struct dentry *dir, struct qstr *name)
dprintk("NFS call remove %s\n", name->name);
dir_attr.valid = 0;
- status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply remove: %d\n", status);
return status;
}
@@ -276,7 +274,7 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr
if (!arg)
return -ENOMEM;
res = (struct nfs_fattr*)(arg + 1);
- arg->fh = NFS_FH(dir);
+ arg->fh = NFS_FH(dir->d_inode);
arg->name = name->name;
arg->len = name->len;
res->valid = 0;
@@ -299,8 +297,8 @@ nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
}
static int
-nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name,
- struct dentry *new_dir, struct qstr *new_name)
+nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ struct inode *new_dir, struct qstr *new_name)
{
struct nfs_fattr old_dir_attr, new_dir_attr;
struct nfs3_renameargs arg = { NFS_FH(old_dir),
@@ -313,18 +311,18 @@ nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name,
dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
old_dir_attr.valid = 0;
new_dir_attr.valid = 0;
- status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0);
- nfs_refresh_inode(old_dir->d_inode, &old_dir_attr);
- nfs_refresh_inode(new_dir->d_inode, &new_dir_attr);
+ status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0);
+ nfs_refresh_inode(old_dir, &old_dir_attr);
+ nfs_refresh_inode(new_dir, &new_dir_attr);
dprintk("NFS reply rename: %d\n", status);
return status;
}
static int
-nfs3_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
+nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{
struct nfs_fattr dir_attr, fattr;
- struct nfs3_linkargs arg = { NFS_FH(dentry), NFS_FH(dir),
+ struct nfs3_linkargs arg = { NFS_FH(inode), NFS_FH(dir),
name->name, name->len };
struct nfs3_linkres res = { &dir_attr, &fattr };
int status;
@@ -332,15 +330,15 @@ nfs3_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
dprintk("NFS call link %s\n", name->name);
dir_attr.valid = 0;
fattr.valid = 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
- nfs_refresh_inode(dentry->d_inode, &fattr);
+ status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0);
+ nfs_refresh_inode(dir, &dir_attr);
+ nfs_refresh_inode(inode, &fattr);
dprintk("NFS reply link: %d\n", status);
return status;
}
static int
-nfs3_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
+nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
struct iattr *sattr, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
@@ -353,14 +351,14 @@ nfs3_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
dir_attr.valid = 0;
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0);
+ nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply symlink: %d\n", status);
return status;
}
static int
-nfs3_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_fattr dir_attr;
@@ -372,14 +370,14 @@ nfs3_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
dprintk("NFS call mkdir %s\n", name->name);
dir_attr.valid = 0;
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
+ nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
static int
-nfs3_proc_rmdir(struct dentry *dir, struct qstr *name)
+nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
{
struct nfs_fattr dir_attr;
struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len };
@@ -387,8 +385,8 @@ nfs3_proc_rmdir(struct dentry *dir, struct qstr *name)
dprintk("NFS call rmdir %s\n", name->name);
dir_attr.valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
+ nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply rmdir: %d\n", status);
return status;
}
@@ -403,16 +401,15 @@ nfs3_proc_rmdir(struct dentry *dir, struct qstr *name)
* readdirplus.
*/
static int
-nfs3_proc_readdir(struct file *file, u64 cookie, void *entry,
+nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
+ u64 cookie, void *entry,
unsigned int size, int plus)
{
- struct dentry *dir = file->f_dentry;
- struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_fattr dir_attr;
struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 };
struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred };
- u32 *verf = NFS_COOKIEVERF(dir->d_inode);
+ u32 *verf = NFS_COOKIEVERF(dir);
int status;
arg.buffer = entry;
@@ -432,14 +429,14 @@ nfs3_proc_readdir(struct file *file, u64 cookie, void *entry,
plus? "plus" : "", (unsigned int) cookie);
dir_attr.valid = 0;
- status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply readdir: %d\n", status);
return status;
}
static int
-nfs3_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
struct nfs_fattr dir_attr;
@@ -459,8 +456,8 @@ nfs3_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
dprintk("NFS call mknod %s %x\n", name->name, rdev);
dir_attr.valid = 0;
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0);
- nfs_refresh_inode(dir->d_inode, &dir_attr);
+ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
+ nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index be935c083..17bb39f36 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -64,34 +64,34 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* One function for each procedure in the NFS protocol.
*/
static int
-nfs_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+nfs_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
{
int status;
dprintk("NFS call getattr\n");
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR,
- NFS_FH(dentry), fattr, 0);
+ status = rpc_call(NFS_CLIENT(inode), NFSPROC_GETATTR,
+ NFS_FH(inode), fattr, 0);
dprintk("NFS reply getattr\n");
return status;
}
static int
-nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+nfs_proc_setattr(struct inode *inode, struct nfs_fattr *fattr,
struct iattr *sattr)
{
- struct nfs_sattrargs arg = { NFS_FH(dentry), sattr };
+ struct nfs_sattrargs arg = { NFS_FH(inode), sattr };
int status;
dprintk("NFS call setattr\n");
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0);
+ status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0);
dprintk("NFS reply setattr\n");
return status;
}
static int
-nfs_proc_lookup(struct dentry *dir, struct qstr *name,
+nfs_proc_lookup(struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len };
@@ -100,32 +100,31 @@ nfs_proc_lookup(struct dentry *dir, struct qstr *name,
dprintk("NFS call lookup %s\n", name->name);
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0);
dprintk("NFS reply lookup: %d\n", status);
return status;
}
static int
-nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz)
+nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz)
{
- struct nfs_readlinkargs args = { NFS_FH(dentry), buffer, bufsiz };
+ struct nfs_readlinkargs args = { NFS_FH(inode), buffer, bufsiz };
struct nfs_readlinkres res = { buffer, bufsiz };
int status;
dprintk("NFS call readlink\n");
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
+ status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
&args, &res, 0);
dprintk("NFS reply readlink: %d\n", status);
return status;
}
static int
-nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
+nfs_proc_read(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, int flags,
loff_t offset, unsigned int count, void *buffer, int *eofp)
{
- struct dentry *dentry = file->f_dentry;
- struct rpc_cred *cred = nfs_file_cred(file);
- struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1,
+ struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1,
{{ buffer, count }, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}} };
struct nfs_readres res = { fattr, count, 0};
@@ -134,7 +133,7 @@ nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
dprintk("NFS call read %d @ %Ld\n", count, (long long)offset);
fattr->valid = 0;
- status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+ status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
dprintk("NFS reply read: %d\n", status);
*eofp = res.eof;
@@ -142,13 +141,12 @@ nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
}
static int
-nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how,
+nfs_proc_write(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, int how,
loff_t offset, unsigned int count,
void *buffer, struct nfs_writeverf *verf)
{
- struct dentry *dentry = file->f_dentry;
- struct rpc_cred *cred = nfs_file_cred(file);
- struct nfs_writeargs arg = {NFS_FH(dentry), offset, count,
+ struct nfs_writeargs arg = {NFS_FH(inode), offset, count,
NFS_FILE_SYNC, 1,
{{buffer, count}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}}};
@@ -160,7 +158,7 @@ nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how,
fattr->valid = 0;
if (how & NFS_RW_SWAP)
flags |= NFS_RPC_SWAPFLAGS;
- status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+ status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
dprintk("NFS reply write: %d\n", status);
verf->committed = NFS_FILE_SYNC; /* NFSv2 always syncs data */
@@ -168,7 +166,7 @@ nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how,
}
static int
-nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+nfs_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { NFS_FH(dir), name->name,
@@ -178,7 +176,7 @@ nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
fattr->valid = 0;
dprintk("NFS call create %s\n", name->name);
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
dprintk("NFS reply create: %d\n", status);
return status;
}
@@ -187,7 +185,7 @@ nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr,
* In NFSv2, mknod is grafted onto the create call.
*/
static int
-nfs_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { NFS_FH(dir), name->name,
@@ -207,26 +205,26 @@ nfs_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr,
}
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
if (status == -EINVAL && S_ISFIFO(mode)) {
sattr->ia_mode = mode;
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
}
dprintk("NFS reply mknod: %d\n", status);
return status;
}
static int
-nfs_proc_remove(struct dentry *dir, struct qstr *name)
+nfs_proc_remove(struct inode *dir, struct qstr *name)
{
struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len };
struct rpc_message msg = { NFSPROC_REMOVE, &arg, NULL, NULL };
int status;
dprintk("NFS call remove %s\n", name->name);
- status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
dprintk("NFS reply remove: %d\n", status);
return status;
@@ -240,7 +238,7 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *
arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
- arg->fh = NFS_FH(dir);
+ arg->fh = NFS_FH(dir->d_inode);
arg->name = name->name;
arg->len = name->len;
msg->rpc_proc = NFSPROC_REMOVE;
@@ -258,8 +256,8 @@ nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
}
static int
-nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name,
- struct dentry *new_dir, struct qstr *new_name)
+nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ struct inode *new_dir, struct qstr *new_name)
{
struct nfs_renameargs arg = { NFS_FH(old_dir), old_name->name,
old_name->len,
@@ -268,26 +266,26 @@ nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name,
int status;
dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name);
- status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0);
+ status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0);
dprintk("NFS reply rename: %d\n", status);
return status;
}
static int
-nfs_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name)
+nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{
- struct nfs_linkargs arg = { NFS_FH(dentry), NFS_FH(dir),
+ struct nfs_linkargs arg = { NFS_FH(inode), NFS_FH(dir),
name->name, name->len };
int status;
dprintk("NFS call link %s\n", name->name);
- status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0);
+ status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0);
dprintk("NFS reply link: %d\n", status);
return status;
}
static int
-nfs_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
+nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
struct iattr *sattr, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
@@ -297,13 +295,13 @@ nfs_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path,
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0);
dprintk("NFS reply symlink: %d\n", status);
return status;
}
static int
-nfs_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
+nfs_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { NFS_FH(dir), name->name, name->len,
@@ -313,19 +311,19 @@ nfs_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr,
dprintk("NFS call mkdir %s\n", name->name);
fattr->valid = 0;
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
static int
-nfs_proc_rmdir(struct dentry *dir, struct qstr *name)
+nfs_proc_rmdir(struct inode *dir, struct qstr *name)
{
struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len };
int status;
dprintk("NFS call rmdir %s\n", name->name);
- status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0);
+ status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0);
dprintk("NFS reply rmdir: %d\n", status);
return status;
}
@@ -338,11 +336,10 @@ nfs_proc_rmdir(struct dentry *dir, struct qstr *name)
* from nfs_readdir by calling the decode_entry function directly.
*/
static int
-nfs_proc_readdir(struct file *file, __u64 cookie, void *entry,
+nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
+ __u64 cookie, void *entry,
unsigned int size, int plus)
{
- struct dentry *dir = file->f_dentry;
- struct rpc_cred *cred = nfs_file_cred(file);
struct nfs_readdirargs arg;
struct nfs_readdirres res;
struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred };
@@ -356,7 +353,7 @@ nfs_proc_readdir(struct file *file, __u64 cookie, void *entry,
res.bufsiz = size;
dprintk("NFS call readdir %d\n", (unsigned int)cookie);
- status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
dprintk("NFS reply readdir: %d\n", status);
return status;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 76fc2f437..e0f7313be 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -36,7 +36,7 @@
struct nfs_read_data {
struct rpc_task task;
- struct dentry *dentry;
+ struct inode *inode;
struct rpc_cred *cred;
struct nfs_readargs args; /* XDR argument struct */
struct nfs_readres res; /* ... and result struct */
@@ -82,10 +82,9 @@ static void nfs_readdata_release(struct rpc_task *task)
* Read a page synchronously.
*/
static int
-nfs_readpage_sync(struct file *file, struct page *page)
+nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct rpc_cred *cred = NULL;
struct nfs_fattr fattr;
loff_t offset = page_offset(page);
char *buffer;
@@ -97,6 +96,9 @@ nfs_readpage_sync(struct file *file, struct page *page)
dprintk("NFS: nfs_readpage_sync(%p)\n", page);
+ if (file)
+ cred = nfs_file_cred(file);
+
/*
* This works now because the socket layer never tries to DMA
* into this buffer directly.
@@ -106,16 +108,16 @@ nfs_readpage_sync(struct file *file, struct page *page)
if (count < rsize)
rsize = count;
- dprintk("NFS: nfs_proc_read(%s, (%s/%s), %Ld, %d, %p)\n",
+ dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n",
NFS_SERVER(inode)->hostname,
- dentry->d_parent->d_name.name, dentry->d_name.name,
+ inode->i_dev, (long long)NFS_FILEID(inode),
(long long)offset, rsize, buffer);
lock_kernel();
- result = NFS_PROTO(inode)->read(file, &fattr, flags, offset,
- rsize, buffer, &eof);
- unlock_kernel();
+ result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
+ offset, rsize, buffer, &eof);
nfs_refresh_inode(inode, &fattr);
+ unlock_kernel();
/*
* Even if we had a partial success we can't mark the page
@@ -180,7 +182,7 @@ nfs_find_read(struct inode *inode, struct page *page)
static inline void
nfs_mark_request_read(struct nfs_page *req)
{
- struct inode *inode = req->wb_dentry->d_inode;
+ struct inode *inode = req->wb_inode;
spin_lock(&nfs_wreq_lock);
if (list_empty(&req->wb_list)) {
@@ -196,9 +198,8 @@ nfs_mark_request_read(struct nfs_page *req)
}
static int
-nfs_readpage_async(struct file *file, struct page *page)
+nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
struct nfs_page *req, *new = NULL;
int result;
@@ -228,7 +229,7 @@ nfs_readpage_async(struct file *file, struct page *page)
}
result = -ENOMEM;
- new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE);
+ new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
if (!new)
break;
}
@@ -264,9 +265,9 @@ nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
data->args.nriov++;
}
req = nfs_list_entry(data->pages.next);
- data->dentry = req->wb_dentry;
+ data->inode = req->wb_inode;
data->cred = req->wb_cred;
- data->args.fh = NFS_FH(req->wb_dentry);
+ data->args.fh = NFS_FH(req->wb_inode);
data->args.offset = page_offset(req->wb_page) + req->wb_offset;
data->args.count = count;
data->res.fattr = &data->fattr;
@@ -292,9 +293,8 @@ nfs_async_read_error(struct list_head *head)
}
static int
-nfs_pagein_one(struct list_head *head, struct dentry *dentry)
+nfs_pagein_one(struct list_head *head, struct inode *inode)
{
- struct inode *inode = dentry->d_inode;
struct rpc_task *task;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_read_data *data;
@@ -328,9 +328,9 @@ nfs_pagein_one(struct list_head *head, struct dentry *dentry)
msg.rpc_cred = data->cred;
/* Start the async call */
- dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n",
+ dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
task->tk_pid,
- dentry->d_parent->d_name.name, dentry->d_name.name,
+ inode->i_dev, (long long)NFS_FILEID(inode),
data->args.count, data->args.nriov);
rpc_clnt_sigmask(clnt, &oldset);
@@ -355,7 +355,7 @@ nfs_pagein_list(struct inode *inode, struct list_head *head)
while (!list_empty(head)) {
pages += nfs_coalesce_requests(head, &one_request, rpages);
req = nfs_list_entry(one_request.next);
- error = nfs_pagein_one(&one_request, req->wb_dentry);
+ error = nfs_pagein_one(&one_request, req->wb_inode);
if (error < 0)
break;
}
@@ -429,8 +429,7 @@ static void
nfs_readpage_result(struct rpc_task *task)
{
struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
- struct dentry *dentry = data->dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = data->inode;
int count = data->res.count;
dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
@@ -451,9 +450,9 @@ nfs_readpage_result(struct rpc_task *task)
kunmap(page);
UnlockPage(page);
- dprintk("NFS: read (%s/%s %d@%Ld)\n",
- req->wb_dentry->d_parent->d_name.name,
- req->wb_dentry->d_name.name,
+ dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
+ req->wb_inode->i_dev,
+ (long long)NFS_FILEID(req->wb_inode),
req->wb_bytes,
(long long)(page_offset(page) + req->wb_offset));
nfs_unlock_request(req);
@@ -473,9 +472,19 @@ nfs_readpage_result(struct rpc_task *task)
int
nfs_readpage(struct file *file, struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode;
int error;
+ if (!file) {
+ struct address_space *mapping = page->mapping;
+ if (!mapping)
+ BUG();
+ inode = (struct inode *)mapping->host;
+ } else
+ inode = file->f_dentry->d_inode;
+ if (!inode)
+ BUG();
+
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
page, PAGE_CACHE_SIZE, page->index);
/*
@@ -491,11 +500,11 @@ nfs_readpage(struct file *file, struct page *page)
error = -1;
if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
- error = nfs_readpage_async(file, page);
+ error = nfs_readpage_async(file, inode, page);
if (error >= 0)
goto out;
- error = nfs_readpage_sync(file, page);
+ error = nfs_readpage_sync(file, inode, page);
if (error < 0 && IS_SWAPFILE(inode))
printk("Aiee.. nfs swap-in of page failed!\n");
out:
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 4960526b4..eba7a859a 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -27,9 +27,8 @@
/* Symlink caching in the page cache is even more simplistic
* and straight-forward than readdir caching.
*/
-static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
+static int nfs_symlink_filler(struct inode *inode, struct page *page)
{
- struct inode *inode = dentry->d_inode;
void *buffer = kmap(page);
int error;
@@ -38,7 +37,7 @@ static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
* XDR response verification will NULL terminate it.
*/
lock_kernel();
- error = NFS_PROTO(inode)->readlink(dentry, buffer,
+ error = NFS_PROTO(inode)->readlink(inode, buffer,
PAGE_CACHE_SIZE - sizeof(u32)-4);
unlock_kernel();
if (error < 0)
@@ -55,15 +54,14 @@ error:
return -EIO;
}
-static char *nfs_getlink(struct dentry *dentry, struct page **ppage)
+static char *nfs_getlink(struct inode *inode, struct page **ppage)
{
- struct inode *inode = dentry->d_inode;
struct page *page;
u32 *p;
/* Caller revalidated the directory inode already. */
page = read_cache_page(&inode->i_data, 0,
- (filler_t *)nfs_symlink_filler, dentry);
+ (filler_t *)nfs_symlink_filler, inode);
if (IS_ERR(page))
goto read_failed;
if (!Page_Uptodate(page))
@@ -81,8 +79,9 @@ read_failed:
static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
+ struct inode *inode = dentry->d_inode;
struct page *page = NULL;
- int res = vfs_readlink(dentry,buffer,buflen,nfs_getlink(dentry,&page));
+ int res = vfs_readlink(dentry,buffer,buflen,nfs_getlink(inode,&page));
if (page) {
kunmap(page);
page_cache_release(page);
@@ -92,8 +91,9 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
+ struct inode *inode = dentry->d_inode;
struct page *page = NULL;
- int res = vfs_follow_link(nd, nfs_getlink(dentry,&page));
+ int res = vfs_follow_link(nd, nfs_getlink(inode,&page));
if (page) {
kunmap(page);
page_cache_release(page);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 230954993..f75190be5 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -77,7 +77,7 @@ static atomic_t nfs_nr_requests = ATOMIC_INIT(0);
*/
struct nfs_write_data {
struct rpc_task task;
- struct dentry *dentry;
+ struct inode *inode;
struct rpc_cred *cred;
struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */
@@ -89,7 +89,8 @@ struct nfs_write_data {
/*
* Local function declarations
*/
-static struct nfs_page * nfs_update_request(struct file*, struct page *page,
+static struct nfs_page * nfs_update_request(struct file*, struct inode *,
+ struct page *,
unsigned int, unsigned int);
static void nfs_strategy(struct inode *inode);
static void nfs_writeback_done(struct rpc_task *);
@@ -167,11 +168,10 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
* Offset is the data offset within the page.
*/
static int
-nfs_writepage_sync(struct file *file, struct page *page,
+nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
unsigned int offset, unsigned int count)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct rpc_cred *cred = NULL;
loff_t base;
unsigned int wsize = NFS_SERVER(inode)->wsize;
int result, refresh = 0, written = 0, flags;
@@ -179,9 +179,13 @@ nfs_writepage_sync(struct file *file, struct page *page,
struct nfs_fattr fattr;
struct nfs_writeverf verf;
+
+ if (file)
+ cred = nfs_file_cred(file);
+
lock_kernel();
- dprintk("NFS: nfs_writepage_sync(%s/%s %d@%Ld)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
+ dprintk("NFS: nfs_writepage_sync(%x/%Ld %d@%Ld)\n",
+ inode->i_dev, (long long)NFS_FILEID(inode),
count, (long long)(page_offset(page) + offset));
buffer = kmap(page) + offset;
@@ -193,7 +197,7 @@ nfs_writepage_sync(struct file *file, struct page *page,
if (count < wsize && !IS_SWAPFILE(inode))
wsize = count;
- result = NFS_PROTO(inode)->write(file, &fattr, flags,
+ result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
base, wsize, buffer, &verf);
nfs_write_attributes(inode, &fattr);
@@ -229,18 +233,18 @@ io_error:
}
static int
-nfs_writepage_async(struct file *file, struct page *page,
+nfs_writepage_async(struct file *file, struct inode *inode, struct page *page,
unsigned int offset, unsigned int count)
{
struct nfs_page *req;
int status;
- req = nfs_update_request(file, page, offset, count);
+ req = nfs_update_request(file, inode, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status < 0)
goto out;
nfs_release_request(req);
- nfs_strategy(file->f_dentry->d_inode);
+ nfs_strategy(inode);
out:
return status;
}
@@ -249,33 +253,48 @@ nfs_writepage_async(struct file *file, struct page *page,
* Write an mmapped page to the server.
*/
int
-nfs_writepage(struct file *file, struct page *page)
+nfs_writepage(struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
- unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ struct inode *inode;
+ unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE;
int err;
+ struct address_space *mapping = page->mapping;
+
+ if (!mapping)
+ BUG();
+ inode = (struct inode *)mapping->host;
+ if (!inode)
+ BUG();
+ end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+ /* Ensure we've flushed out any previous writes */
+ nfs_wb_page(inode,page);
/* easy case */
if (page->index < end_index)
goto do_it;
/* things got complicated... */
offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+
/* OK, are we completely out? */
+ err = -EIO;
if (page->index >= end_index+1 || !offset)
- return -EIO;
+ goto out;
do_it:
if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
- err = nfs_writepage_async(file, page, 0, offset);
+ err = nfs_writepage_async(NULL, inode, page, 0, offset);
if (err >= 0)
goto out_ok;
}
- err = nfs_writepage_sync(file, page, 0, offset);
- if ( err == offset)
- goto out_ok;
+ err = nfs_writepage_sync(NULL, inode, page, 0, offset);
+ if ( err == offset) {
+out_ok:
+ err = 0;
+ }
+out:
+ UnlockPage(page);
return err;
- out_ok:
- return 0;
}
/*
@@ -315,6 +334,8 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
return;
if (!NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
+ if (list_empty(&inode->u.nfs_i.writeback))
+ atomic_inc(&inode->i_count);
inode->u.nfs_i.npages++;
list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
req->wb_count++;
@@ -334,12 +355,14 @@ nfs_inode_remove_request(struct nfs_page *req)
}
if (!NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
- inode = req->wb_dentry->d_inode;
+ inode = req->wb_inode;
list_del(&req->wb_hash);
INIT_LIST_HEAD(&req->wb_hash);
inode->u.nfs_i.npages--;
if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
+ if (list_empty(&inode->u.nfs_i.writeback))
+ iput(inode);
if (!nfs_have_writebacks(inode) && !nfs_have_read(inode))
inode_remove_flushd(inode);
spin_unlock(&nfs_wreq_lock);
@@ -422,7 +445,7 @@ void nfs_list_remove_request(struct nfs_page *req)
static inline void
nfs_mark_request_dirty(struct nfs_page *req)
{
- struct inode *inode = req->wb_dentry->d_inode;
+ struct inode *inode = req->wb_inode;
spin_lock(&nfs_wreq_lock);
if (list_empty(&req->wb_list)) {
@@ -443,7 +466,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
static inline int
nfs_dirty_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_dentry->d_inode;
+ struct inode *inode = req->wb_inode;
return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
}
@@ -454,7 +477,7 @@ nfs_dirty_request(struct nfs_page *req)
static inline void
nfs_mark_request_commit(struct nfs_page *req)
{
- struct inode *inode = req->wb_dentry->d_inode;
+ struct inode *inode = req->wb_inode;
spin_lock(&nfs_wreq_lock);
if (list_empty(&req->wb_list)) {
@@ -477,11 +500,10 @@ nfs_mark_request_commit(struct nfs_page *req)
* when we reach the hard limit on the number of dirty pages.
* It should be safe to sleep here.
*/
-struct nfs_page *nfs_create_request(struct file *file, struct page *page,
+struct nfs_page *nfs_create_request(struct file *file, struct inode *inode,
+ struct page *page,
unsigned int offset, unsigned int count)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct nfs_page *req = NULL;
long timeout;
@@ -533,9 +555,15 @@ struct nfs_page *nfs_create_request(struct file *file, struct page *page,
req->wb_offset = offset;
req->wb_bytes = count;
req->wb_file = file;
- get_file(file);
- req->wb_dentry = dentry;
- req->wb_cred = nfs_file_cred(file);
+
+ /* If we have a struct file, use its cached credentials
+ * else cache the current process' credentials. */
+ if (file) {
+ get_file(file);
+ req->wb_cred = nfs_file_cred(file);
+ } else
+ req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ req->wb_inode = inode;
req->wb_count = 1;
/* register request's existence */
@@ -554,7 +582,7 @@ struct nfs_page *nfs_create_request(struct file *file, struct page *page,
void
nfs_release_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_dentry->d_inode;
+ struct inode *inode = req->wb_inode;
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct page *page = req->wb_page;
@@ -576,7 +604,11 @@ nfs_release_request(struct nfs_page *req)
if (NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: Request released while still locked!\n");
- fput(req->wb_file);
+ /* Release struct file or cached credential */
+ if (req->wb_file)
+ fput(req->wb_file);
+ else
+ rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
page_cache_release(page);
nfs_page_free(req);
/* wake up anyone waiting to allocate a request */
@@ -599,7 +631,7 @@ nfs_release_request(struct nfs_page *req)
static int
nfs_wait_on_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_dentry->d_inode;
+ struct inode *inode = req->wb_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
if (!NFS_WBACK_BUSY(req))
@@ -814,10 +846,9 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned
* Note: Should always be called with the Page Lock held!
*/
static struct nfs_page *
-nfs_update_request(struct file* file, struct page *page,
+nfs_update_request(struct file* file, struct inode *inode, struct page *page,
unsigned int offset, unsigned int bytes)
{
- struct inode *inode = file->f_dentry->d_inode;
struct nfs_page *req, *new = NULL;
unsigned long rqend, end;
@@ -857,7 +888,7 @@ nfs_update_request(struct file* file, struct page *page,
*/
if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT)
nfs_wb_file(inode, file);
- new = nfs_create_request(file, page, offset, bytes);
+ new = nfs_create_request(file, inode, page, offset, bytes);
if (!new)
return ERR_PTR(-ENOMEM);
/* If the region is locked, adjust the timeout */
@@ -995,7 +1026,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
* page synchronously.
*/
if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
- return nfs_writepage_sync(file, page, offset, count);
+ return nfs_writepage_sync(file, inode, page, offset, count);
/*
* Try to find an NFS request corresponding to this page
@@ -1004,7 +1035,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
* it out now.
*/
do {
- req = nfs_update_request(file, page, offset, count);
+ req = nfs_update_request(file, inode, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status != -EBUSY)
break;
@@ -1068,9 +1099,9 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
data->args.nriov++;
}
req = nfs_list_entry(data->pages.next);
- data->dentry = req->wb_dentry;
+ data->inode = req->wb_inode;
data->cred = req->wb_cred;
- data->args.fh = NFS_FH(req->wb_dentry);
+ data->args.fh = NFS_FH(req->wb_inode);
data->args.offset = page_offset(req->wb_page) + req->wb_offset;
data->args.count = count;
data->res.fattr = &data->fattr;
@@ -1088,9 +1119,8 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
* that has been written but not committed.
*/
static int
-nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
+nfs_flush_one(struct list_head *head, struct inode *inode, int how)
{
- struct inode *inode = dentry->d_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_write_data *data;
struct rpc_task *task;
@@ -1134,10 +1164,10 @@ nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
msg.rpc_resp = &data->res;
msg.rpc_cred = data->cred;
- dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n",
+ dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
task->tk_pid,
- dentry->d_parent->d_name.name,
- dentry->d_name.name,
+ inode->i_dev,
+ (long long)NFS_FILEID(inode),
data->args.count, data->args.nriov);
rpc_clnt_sigmask(clnt, &oldset);
@@ -1167,7 +1197,7 @@ nfs_flush_list(struct inode *inode, struct list_head *head, int how)
while (!list_empty(head)) {
pages += nfs_coalesce_requests(head, &one_request, wpages);
req = nfs_list_entry(one_request.next);
- error = nfs_flush_one(&one_request, req->wb_dentry, how);
+ error = nfs_flush_one(&one_request, req->wb_inode, how);
if (error < 0)
break;
}
@@ -1193,8 +1223,7 @@ nfs_writeback_done(struct rpc_task *task)
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
struct nfs_writeargs *argp = &data->args;
struct nfs_writeres *resp = &data->res;
- struct dentry *dentry = data->dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = data->inode;
struct nfs_page *req;
struct page *page;
@@ -1249,9 +1278,9 @@ nfs_writeback_done(struct rpc_task *task)
kunmap(page);
- dprintk("NFS: write (%s/%s %d@%Ld)",
- req->wb_dentry->d_parent->d_name.name,
- req->wb_dentry->d_name.name,
+ dprintk("NFS: write (%x/%Ld %d@%Ld)",
+ req->wb_inode->i_dev,
+ (long long)NFS_FILEID(req->wb_inode),
req->wb_bytes,
(long long)(page_offset(page) + req->wb_offset));
@@ -1292,7 +1321,6 @@ static void
nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
{
struct nfs_page *first, *last;
- struct dentry *dentry;
struct inode *inode;
loff_t start, end, len;
@@ -1303,8 +1331,7 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
INIT_LIST_HEAD(head);
first = nfs_list_entry(data->pages.next);
last = nfs_list_entry(data->pages.prev);
- dentry = first->wb_dentry;
- inode = dentry->d_inode;
+ inode = first->wb_inode;
/*
* Determine the offset range of requests in the COMMIT call.
@@ -1317,9 +1344,9 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
if (end >= inode->i_size || len < 0 || len > (~((u32)0) >> 1))
len = 0;
- data->dentry = dentry;
+ data->inode = inode;
data->cred = first->wb_cred;
- data->args.fh = NFS_FH(dentry);
+ data->args.fh = NFS_FH(inode);
data->args.offset = start;
data->res.count = data->args.count = (u32)len;
data->res.fattr = &data->fattr;
@@ -1352,7 +1379,7 @@ nfs_commit_list(struct list_head *head, int how)
/* Set up the argument struct */
nfs_commit_rpcsetup(head, data);
req = nfs_list_entry(data->pages.next);
- clnt = NFS_CLIENT(req->wb_dentry->d_inode);
+ clnt = NFS_CLIENT(req->wb_inode);
rpc_init_task(task, clnt, nfs_commit_done, flags);
task->tk_calldata = data;
@@ -1389,8 +1416,7 @@ nfs_commit_done(struct rpc_task *task)
struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
struct nfs_writeres *resp = &data->res;
struct nfs_page *req;
- struct dentry *dentry = data->dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = data->inode;
dprintk("NFS: %4d nfs_commit_done (status %d)\n",
task->tk_pid, task->tk_status);
@@ -1400,9 +1426,9 @@ nfs_commit_done(struct rpc_task *task)
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
- dprintk("NFS: commit (%s/%s %d@%Ld)",
- req->wb_dentry->d_parent->d_name.name,
- req->wb_dentry->d_name.name,
+ dprintk("NFS: commit (%x/%Ld %d@%Ld)",
+ req->wb_inode->i_dev,
+ (long long)NFS_FILEID(req->wb_inode),
req->wb_bytes,
(long long)(page_offset(req->wb_page) + req->wb_offset));
if (task->tk_status < 0) {
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 49d2160a6..ad99eb13b 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -557,7 +557,8 @@ ntfs_bmap(struct inode *ino,int block)
#endif
/* It's fscking broken. */
-
+/* FIXME: [bm]map code is disabled until ntfs_get_block gets sorted! */
+/*
static int ntfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
{
BUG();
@@ -573,6 +574,7 @@ static struct file_operations ntfs_file_operations = {
};
static struct inode_operations ntfs_inode_operations;
+*/
static struct file_operations ntfs_dir_operations = {
read: generic_read_dir,
@@ -587,7 +589,8 @@ static struct inode_operations ntfs_dir_inode_operations = {
#endif
};
-static int ntfs_writepage(struct file *file, struct page *page)
+/*
+static int ntfs_writepage(struct page *page)
{
return block_write_full_page(page,ntfs_get_block);
}
@@ -612,6 +615,8 @@ struct address_space_operations ntfs_aops = {
commit_write: generic_commit_write,
bmap: _ntfs_bmap
};
+*/
+
/* ntfs_read_inode is called by the Virtual File System (the kernel layer that
* deals with filesystems) when iget is called requesting an inode not already
* present in the inode table. Typically filesystems have separate
@@ -664,7 +669,10 @@ static void ntfs_read_inode(struct inode* inode)
else
{
inode->i_size=data->size;
- can_mmap=!data->resident && !data->compressed;
+ /* FIXME: once ntfs_get_block is implemented, uncomment the
+ * next line and remove the can_mmap = 0; */
+ /* can_mmap=!data->resident && !data->compressed;*/
+ can_mmap = 0;
}
/* get the file modification times from the standard information */
si=ntfs_find_attr(ino,vol->at_standard_information,NULL);
@@ -687,12 +695,17 @@ static void ntfs_read_inode(struct inode* inode)
}
else
{
- if (can_mmap) {
+ /* As long as ntfs_get_block() is just a call to BUG() do not
+ * define any [bm]map ops or we get the BUG() whenever someone
+ * runs mc or mpg123 on an ntfs partition!
+ * FIXME: Uncomment the below code when ntfs_get_block is
+ * implemented. */
+ /* if (can_mmap) {
inode->i_op = &ntfs_inode_operations;
inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = &ntfs_aops;
inode->u.ntfs_i.mmu_private = inode->i_size;
- } else {
+ } else */ {
inode->i_op=&ntfs_inode_operations_nobmap;
inode->i_fop=&ntfs_file_operations_nommap;
}
@@ -931,8 +944,7 @@ static int __init init_ntfs_fs(void)
/* Comment this if you trust klogd. There are reasons not to trust it
*/
#if defined(DEBUG) && !defined(MODULE)
- extern int console_loglevel;
- console_loglevel=15;
+ console_verbose();
#endif
printk(KERN_NOTICE "NTFS version " NTFS_VERSION "\n");
SYSCTL(1);
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index e58b04e02..e46ef0b25 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -43,7 +43,7 @@ static struct file_operations proc_file_operations = {
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
-/* 4K page size but our output routines use some slack for overruns */
+/* buffer size is one page but our output routines use some slack for overruns */
#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
static ssize_t
@@ -336,6 +336,7 @@ int proc_readdir(struct file * filp,
* the /proc directory.
*/
static struct file_operations proc_dir_operations = {
+ read: generic_read_dir,
readdir: proc_readdir,
};
diff --git a/fs/proc/root.c b/fs/proc/root.c
index cae861960..c54369a32 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -82,6 +82,7 @@ static int proc_root_readdir(struct file * filp,
* directory handling functions for that..
*/
static struct file_operations proc_root_operations = {
+ read: generic_read_dir,
readdir: proc_root_readdir,
};
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 78dbc34f0..45a945209 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -415,7 +415,7 @@ static void qnx4_put_super(struct super_block *sb)
return;
}
-static int qnx4_writepage(struct file *file, struct page *page)
+static int qnx4_writepage(struct page *page)
{
return block_write_full_page(page,qnx4_get_block);
}
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 31461669c..36fa933a4 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -78,7 +78,7 @@ static int ramfs_readpage(struct file *file, struct page * page)
* Writing: just make sure the page gets marked dirty, so that
* the page stealer won't grab it.
*/
-static int ramfs_writepage(struct file *file, struct page *page)
+static int ramfs_writepage(struct page *page)
{
SetPageDirty(page);
return 0;
diff --git a/fs/readdir.c b/fs/readdir.c
index cd8f7ad3d..16eba6383 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -325,4 +325,3 @@ out_putf:
out:
return error;
}
-
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index b2d5c4099..7b62899c1 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -124,7 +124,7 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
qname.len = entry->len;
entry->ino = find_inode_number(dentry, &qname);
if (!entry->ino)
- entry->ino = smb_invent_inos(1);
+ entry->ino = iunique(dentry->d_sb, 2);
}
if (filldir(dirent, entry->name, entry->len,
@@ -325,7 +325,7 @@ smb_lookup(struct inode *dir, struct dentry *dentry)
goto add_entry;
if (!error) {
error = -EACCES;
- finfo.f_ino = smb_invent_inos(1);
+ finfo.f_ino = iunique(dentry->d_sb, 2);
inode = smb_iget(dir->i_sb, &finfo);
if (inode) {
add_entry:
@@ -362,7 +362,7 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
goto out_close;
smb_renew_times(dentry);
- fattr.f_ino = smb_invent_inos(1);
+ fattr.f_ino = iunique(dentry->d_sb, 2);
inode = smb_iget(dentry->d_sb, &fattr);
if (!inode)
goto out_no_inode;
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 135e8707c..79627f880 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -48,8 +48,7 @@ smb_readpage_sync(struct dentry *dentry, struct page *page)
DENTRY_PATH(dentry), count, offset, rsize);
result = smb_open(dentry, SMB_O_RDONLY);
- if (result < 0)
- {
+ if (result < 0) {
PARANOIA("%s/%s open failed, error=%d\n",
DENTRY_PATH(dentry), result);
goto io_error;
@@ -59,7 +58,7 @@ smb_readpage_sync(struct dentry *dentry, struct page *page)
if (count < rsize)
rsize = count;
- result = smb_proc_read(dentry, offset, rsize, buffer);
+ result = smb_proc_read(dentry->d_inode, offset, rsize, buffer);
if (result < 0)
goto io_error;
@@ -82,7 +81,7 @@ io_error:
}
/*
- * We are called with the page locked and the caller unlocks.
+ * We are called with the page locked and we unlock it when done.
*/
static int
smb_readpage(struct file *file, struct page *page)
@@ -103,25 +102,27 @@ smb_readpage(struct file *file, struct page *page)
* Offset is the data offset within the page.
*/
static int
-smb_writepage_sync(struct dentry *dentry, struct page *page,
+smb_writepage_sync(struct inode *inode, struct page *page,
unsigned long offset, unsigned int count)
{
- struct inode *inode = dentry->d_inode;
u8 *buffer = page_address(page) + offset;
- int wsize = smb_get_wsize(server_from_dentry(dentry));
+ int wsize = smb_get_wsize(server_from_inode(inode));
int result, written = 0;
offset += page->index << PAGE_CACHE_SHIFT;
- VERBOSE("file %s/%s, count=%d@%ld, wsize=%d\n",
- DENTRY_PATH(dentry), count, offset, wsize);
+ VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
+ inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
do {
if (count < wsize)
wsize = count;
- result = smb_proc_write(dentry, offset, wsize, buffer);
- if (result < 0)
+ result = smb_proc_write(inode, offset, wsize, buffer);
+ if (result < 0) {
+ PARANOIA("failed write, wsize=%d, result=%d\n",
+ wsize, result);
break;
+ }
/* N.B. what if result < wsize?? */
#ifdef SMBFS_PARANOIA
if (result < wsize)
@@ -147,17 +148,25 @@ smb_writepage_sync(struct dentry *dentry, struct page *page,
* Write a page to the server. This will be used for NFS swapping only
* (for now), and we currently do this synchronously only.
*
- * We are called with the page locked and the caller unlocks.
+ * We are called with the page locked and we unlock it when done.
*/
static int
-smb_writepage(struct file *file, struct page *page)
+smb_writepage(struct page *page)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ struct address_space *mapping = page->mapping;
+ struct inode *inode;
+ unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE;
int err;
+ if (!mapping)
+ BUG();
+ inode = (struct inode *)mapping->host;
+ if (!inode)
+ BUG();
+
+ end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
/* easy case */
if (page->index < end_index)
goto do_it;
@@ -168,8 +177,9 @@ smb_writepage(struct file *file, struct page *page)
return -EIO;
do_it:
get_page(page);
- err = smb_writepage_sync(dentry, page, 0, offset);
+ err = smb_writepage_sync(inode, page, 0, offset);
SetPageUptodate(page);
+ UnlockPage(page);
put_page(page);
return err;
}
@@ -183,7 +193,7 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset,
DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry),
count, (page->index << PAGE_CACHE_SHIFT)+offset);
- return smb_writepage_sync(dentry, page, offset, count);
+ return smb_writepage_sync(dentry->d_inode, page, offset, count);
}
static ssize_t
@@ -308,8 +318,16 @@ out:
static int
smb_file_open(struct inode *inode, struct file * file)
{
+ int result;
+ struct dentry *dentry = file->f_dentry;
+ int smb_mode = (file->f_mode & O_ACCMODE) - 1;
+
lock_kernel();
+ result = smb_open(dentry, smb_mode);
+ if (result)
+ goto out;
inode->u.smbfs_i.openers++;
+out:
unlock_kernel();
return 0;
}
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index bcc900626..e502fb60b 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -53,22 +53,6 @@ static struct super_operations smb_sops =
statfs: smb_statfs,
};
-/* FIXME: Look at all inodes whether so that we do not get duplicate
- * inode numbers. */
-
-unsigned long
-smb_invent_inos(unsigned long n)
-{
- static unsigned long ino = 2;
-
- if (ino + 2*n < ino)
- {
- /* wrap around */
- ino = 2;
- }
- ino += n;
- return ino;
-}
/* We are always generating a new inode here */
struct inode *
@@ -282,7 +266,7 @@ out:
static void
smb_delete_inode(struct inode *ino)
{
- DEBUG1("\n");
+ DEBUG1("ino=%ld\n", ino->i_ino);
lock_kernel();
if (smb_close(ino))
PARANOIA("could not close inode %ld\n", ino->i_ino);
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 7863cd2da..f0444f97d 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -1072,9 +1072,9 @@ smb_close_fileid(struct dentry *dentry, __u16 fileid)
file-id would not be valid after a reconnection. */
int
-smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
+smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
{
- struct smb_sb_info *server = server_from_dentry(dentry);
+ struct smb_sb_info *server = server_from_inode(inode);
__u16 returned_count, data_len;
unsigned char *buf;
int result;
@@ -1082,7 +1082,7 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
smb_lock_server(server);
smb_setup_header(server, SMBread, 5, 0);
buf = server->packet;
- WSET(buf, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
+ WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid);
WSET(buf, smb_vwv1, count);
DSET(buf, smb_vwv2, offset);
WSET(buf, smb_vwv4, 0);
@@ -1114,25 +1114,26 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
result = data_len;
out:
- VERBOSE("file %s/%s, count=%d, result=%d\n",
- DENTRY_PATH(dentry), count, result);
+ VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
+ inode->ino, inode->u.smbfs_i.fileid, count, result);
smb_unlock_server(server);
return result;
}
int
-smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data)
+smb_proc_write(struct inode *inode, off_t offset, int count, const char *data)
{
- struct smb_sb_info *server = server_from_dentry(dentry);
+ struct smb_sb_info *server = server_from_inode(inode);
int result;
__u8 *p;
- VERBOSE("file %s/%s, count=%d@%ld, packet_size=%d\n",
- DENTRY_PATH(dentry), count, offset, server->packet_size);
+ VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
+ inode->ino, inode->u.smbfs_i.fileid, count, offset,
+ server->packet_size);
smb_lock_server(server);
p = smb_setup_header(server, SMBwrite, 5, count + 3);
- WSET(server->packet, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
+ WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
WSET(server->packet, smb_vwv1, count);
DSET(server->packet, smb_vwv2, offset);
WSET(server->packet, smb_vwv4, 0);
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 66dbd9efb..cb1e697fc 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -163,12 +163,12 @@ smb_data_ready(struct sock *sk, int len)
found_data(sk);
return;
}
- job->cb.next = NULL;
+ INIT_LIST_HEAD(&job->cb.list);
job->cb.sync = 0;
job->cb.routine = smb_data_callback;
job->cb.data = job;
job->sk = sk;
- queue_task(&job->cb, &tq_scheduler);
+ schedule_task(&job->cb);
}
int
diff --git a/fs/stat.c b/fs/stat.c
index e07b237e4..3d7efa0ad 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -25,7 +25,7 @@ do_revalidate(struct dentry *dentry)
}
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
/*
* For backward compatibility? Maybe this should be moved
@@ -126,7 +126,7 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
}
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
/*
* For backward compatibility? Maybe this should be moved
* into arch/i386 instead?
@@ -162,7 +162,7 @@ asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
return error;
}
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
/*
* For backward compatibility? Maybe this should be moved
@@ -200,7 +200,7 @@ asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
return error;
}
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
/*
* For backward compatibility? Maybe this should be moved
diff --git a/fs/super.c b/fs/super.c
index 4f2e3908a..1c0b48c11 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1037,13 +1037,13 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
}
spin_lock(&dcache_lock);
- if (atomic_read(&mnt->mnt_count) > 2) {
- spin_unlock(&dcache_lock);
- mntput(mnt);
- return -EBUSY;
- }
if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
+ if (atomic_read(&mnt->mnt_count) > 2) {
+ spin_unlock(&dcache_lock);
+ mntput(mnt);
+ return -EBUSY;
+ }
if (sb->s_type->fs_flags & FS_SINGLE)
put_filesystem(sb->s_type);
/* We hold two references, so mntput() is safe */
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 7e5f6c54a..1fb7beaa8 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -916,7 +916,7 @@ struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create)
return NULL;
}
-static int sysv_writepage(struct file *file, struct page *page)
+static int sysv_writepage(struct page *page)
{
return block_write_full_page(page,sysv_get_block);
}
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 7e8ac9b7d..3895d769b 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -67,7 +67,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page)
return 0;
}
-static int udf_adinicb_writepage(struct file *file, struct page *page)
+static int udf_adinicb_writepage(struct page *page)
{
struct inode *inode = (struct inode *)page->mapping->host;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 83a34f258..3783b43fd 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -125,7 +125,7 @@ void udf_discard_prealloc(struct inode * inode)
udf_trunc(inode);
}
-static int udf_writepage(struct file *file, struct page *page)
+static int udf_writepage(struct page *page)
{
return block_write_full_page(page, udf_get_block);
}
@@ -202,7 +202,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
mark_buffer_dirty(bh);
udf_release_data(bh);
- inode->i_data.a_ops->writepage(NULL, page);
+ inode->i_data.a_ops->writepage(page);
UnlockPage(page);
page_cache_release(page);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 10a9d9be4..55830ac19 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -518,7 +518,7 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
return NULL;
}
-static int ufs_writepage(struct file *file, struct page *page)
+static int ufs_writepage(struct page *page)
{
return block_write_full_page(page,ufs_getfrag_block);
}