summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-28 22:00:09 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-28 22:00:09 +0000
commit1a1d77dd589de5a567fa95e36aa6999c704ceca4 (patch)
tree141e31f89f18b9fe0831f31852e0435ceaccafc5 /fs
parentfb9c690a18b3d66925a65b17441c37fa14d4370b (diff)
Merge with 2.4.0-test7.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in4
-rw-r--r--fs/adfs/dir.c6
-rw-r--r--fs/affs/dir.c6
-rw-r--r--fs/autofs/root.c6
-rw-r--r--fs/autofs4/expire.c6
-rw-r--r--fs/bfs/dir.c2
-rw-r--r--fs/block_dev.c5
-rw-r--r--fs/buffer.c28
-rw-r--r--fs/coda/dir.c2
-rw-r--r--fs/cramfs/inode.c2
-rw-r--r--fs/dcache.c13
-rw-r--r--fs/devfs/base.c6
-rw-r--r--fs/devpts/root.c6
-rw-r--r--fs/efs/dir.c2
-rw-r--r--fs/exec.c27
-rw-r--r--fs/ext2/dir.c11
-rw-r--r--fs/fat/dir.c11
-rw-r--r--fs/fcntl.c100
-rw-r--r--fs/hfs/dir_cap.c15
-rw-r--r--fs/hfs/dir_dbl.c11
-rw-r--r--fs/hfs/dir_nat.c16
-rw-r--r--fs/hpfs/dir.c6
-rw-r--r--fs/hpfs/hpfs.h6
-rw-r--r--fs/hpfs/map.c5
-rw-r--r--fs/inode.c3
-rw-r--r--fs/ioctl.c4
-rw-r--r--fs/isofs/dir.c6
-rw-r--r--fs/jffs/inode-v23.c13
-rw-r--r--fs/locks.c260
-rw-r--r--fs/minix/dir.c2
-rw-r--r--fs/namei.c3
-rw-r--r--fs/ncpfs/dir.c8
-rw-r--r--fs/nfs/dir.c10
-rw-r--r--fs/nfs/inode.c9
-rw-r--r--fs/nfs/proc.c4
-rw-r--r--fs/nfs/write.c42
-rw-r--r--fs/nfsd/nfs3xdr.c10
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/nfsd/nfsxdr.c2
-rw-r--r--fs/nls/Config.in3
-rw-r--r--fs/ntfs/fs.c6
-rw-r--r--fs/open.c33
-rw-r--r--fs/openpromfs/inode.c14
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/array.c15
-rw-r--r--fs/proc/base.c17
-rw-r--r--fs/proc/generic.c9
-rw-r--r--fs/qnx4/dir.c2
-rw-r--r--fs/readdir.c102
-rw-r--r--fs/romfs/inode.c7
-rw-r--r--fs/smbfs/ChangeLog11
-rw-r--r--fs/smbfs/Makefile2
-rw-r--r--fs/smbfs/dir.c33
-rw-r--r--fs/smbfs/getopt.c61
-rw-r--r--fs/smbfs/getopt.h15
-rw-r--r--fs/smbfs/inode.c159
-rw-r--r--fs/smbfs/proc.c369
-rw-r--r--fs/smbfs/sock.c14
-rw-r--r--fs/stat.c8
-rw-r--r--fs/super.c89
-rw-r--r--fs/sysv/dir.c2
-rw-r--r--fs/udf/dir.c6
-rw-r--r--fs/ufs/dir.c5
-rw-r--r--fs/umsdos/dir.c6
-rw-r--r--fs/umsdos/rdir.c7
65 files changed, 1249 insertions, 428 deletions
diff --git a/fs/Config.in b/fs/Config.in
index e48f75496..183aab8f8 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -99,7 +99,9 @@ if [ "$CONFIG_NET" = "y" ]; then
fi
dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
-
+ if [ "$CONFIG_SMB_FS" != "n" ]; then
+ string 'Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE ""
+ fi
if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS
source fs/ncpfs/Config.in
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 21a277344..b650f421f 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -40,12 +40,12 @@ adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
switch ((unsigned long)filp->f_pos) {
case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
goto free_out;
filp->f_pos += 1;
case 1:
- if (filldir(dirent, "..", 2, 1, dir.parent_id) < 0)
+ if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0)
goto free_out;
filp->f_pos += 1;
@@ -60,7 +60,7 @@ adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto unlock_out;
while (ops->getnext(&dir, &obj) == 0) {
if (filldir(dirent, obj.name, obj.name_len,
- filp->f_pos, obj.file_id) < 0)
+ filp->f_pos, obj.file_id, DT_UNKNOWN) < 0)
goto unlock_out;
filp->f_pos += 1;
}
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index aba6b0baa..c21e5771d 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -72,14 +72,14 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (filp->f_pos == 0) {
filp->private_data = (void *)0;
- if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
+ if (filldir(dirent,".",1,filp->f_pos,inode->i_ino,DT_DIR) < 0) {
return 0;
}
++filp->f_pos;
stored++;
}
if (filp->f_pos == 1) {
- if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
+ if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode),DT_DIR) < 0) {
return stored;
}
filp->f_pos = 2;
@@ -135,7 +135,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
namelen,name,ino,i);
filp->private_data = (void *)ino;
- if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
+ if (filldir(dirent,name,namelen,filp->f_pos,ino,DT_UNKNOWN) < 0)
goto readdir_done;
filp->private_data = (void *)(unsigned long)i;
affs_brelse(fh_bh);
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 4ba567499..0df477648 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -54,19 +54,19 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
switch(nr)
{
case 0:
- if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
default:
while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
- if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
+ if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0)
return 0;
filp->f_pos = nr;
}
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index aca401b73..9d21624bc 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -23,7 +23,9 @@ static int is_tree_busy(struct vfsmount *mnt)
int count;
spin_lock(&dcache_lock);
- count = atomic_read(&mnt->mnt_count);
+ count = atomic_read(&mnt->mnt_count) - 2;
+ if (!is_autofs4_dentry(mnt->mnt_mountpoint))
+ count--;
repeat:
next = this_parent->mnt_mounts.next;
resume:
@@ -33,7 +35,7 @@ resume:
mnt_child);
next = tmp->next;
/* Decrement count for unused children */
- count += atomic_read(&p->mnt_count) - 1;
+ count += atomic_read(&p->mnt_count) - 2;
if (!list_empty(&p->mnt_mounts)) {
this_parent = p;
goto repeat;
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 76e55be5d..721739e31 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -50,7 +50,7 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
de = (struct bfs_dirent *)(bh->b_data + offset);
if (de->ino) {
int size = strnlen(de->name, BFS_NAMELEN);
- if (filldir(dirent, de->name, size, f->f_pos, de->ino) < 0) {
+ if (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) {
brelse(bh);
return 0;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 7546705fa..21bc086e3 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -5,6 +5,7 @@
*/
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fcntl.h>
@@ -347,7 +348,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
}
}
-void bdev_init(void)
+void __init bdev_init(void)
{
int i;
struct list_head *head = bdev_hashtable;
@@ -364,7 +365,7 @@ void bdev_init(void)
0, SLAB_HWCACHE_ALIGN, init_once,
NULL);
if (!bdev_cachep)
- panic("cannot create bdev slab cache");
+ panic("Cannot create bdev_cache SLAB cache");
}
/*
diff --git a/fs/buffer.c b/fs/buffer.c
index b296dad7b..ca6e2f919 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -119,7 +119,7 @@ union bdflush_param {
when trying to refill buffers. */
int interval; /* jiffies delay between kupdate flushes */
int age_buffer; /* Time for normal buffer to age before we flush it */
- int age_super; /* Time for superblock to age before we flush it */
+ int dummy1; /* unused, was age_super */
int dummy2; /* unused */
int dummy3; /* unused */
} b_un;
@@ -894,7 +894,7 @@ void balance_dirty(kdev_t dev)
static __inline__ void __mark_dirty(struct buffer_head *bh, int flag)
{
- bh->b_flushtime = jiffies + (flag ? bdf_prm.b_un.age_super : bdf_prm.b_un.age_buffer);
+ bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer;
refile_buffer(bh);
}
@@ -1714,8 +1714,10 @@ int generic_commit_write(struct file *file, struct page *page,
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
__block_commit_write(inode,page,from,to);
kunmap(page);
- if (pos > inode->i_size)
+ if (pos > inode->i_size) {
inode->i_size = pos;
+ mark_inode_dirty(inode);
+ }
return 0;
}
@@ -1781,15 +1783,12 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
* for them to complete. Clean up the buffer_heads afterwards.
*/
-static int do_kio(int rw, int nr, struct buffer_head *bh[], int size)
+static int wait_kio(int rw, int nr, struct buffer_head *bh[], int size)
{
int iosize;
int i;
struct buffer_head *tmp;
- if (rw == WRITE)
- rw = WRITERAW;
- ll_rw_block(rw, nr, bh);
iosize = 0;
spin_lock(&unused_list_lock);
@@ -1840,6 +1839,7 @@ 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;
@@ -1891,9 +1891,10 @@ 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_dev = dev;
+ tmp->b_rdev = tmp->b_dev = dev;
tmp->b_blocknr = blocknr;
- tmp->b_state = 1 << BH_Mapped;
+ tmp->b_rsector = blocknr*sectors;
+ tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req);
if (rw == WRITE) {
set_bit(BH_Uptodate, &tmp->b_state);
@@ -1905,12 +1906,13 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
offset += size;
atomic_inc(&iobuf->io_count);
-
+
+ generic_make_request(rw, tmp);
/*
- * Start the IO if we have got too much
+ * Wait for IO if we have got too much
*/
if (bhind >= KIO_MAX_SECTORS) {
- err = do_kio(rw, bhind, bh, size);
+ err = wait_kio(rw, bhind, bh, size);
if (err >= 0)
transferred += err;
else
@@ -1928,7 +1930,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
/* Is there any IO still left to submit? */
if (bhind) {
- err = do_kio(rw, bhind, bh, size);
+ err = wait_kio(rw, bhind, bh, size);
if (err >= 0)
transferred += err;
else
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index e53933710..a51bfc647 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -748,7 +748,7 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
char *name = vdirent->d_name;
errfill = filldir(getdent, name, namlen,
- offs, ino);
+ offs, ino, DT_UNKNOWN);
CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos, string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill);
/* errfill means no space for filling in this round */
if ( errfill < 0 ) {
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 8b0a91426..a0cf6ba97 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -258,7 +258,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
namelen--;
}
- error = filldir(dirent, name, namelen, offset, CRAMINO(de));
+ error = filldir(dirent, name, namelen, offset, CRAMINO(de), de->mode >> 12);
if (error)
break;
diff --git a/fs/dcache.c b/fs/dcache.c
index e2bcbe6a3..214f0da2e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1189,7 +1189,9 @@ static void __init dcache_init(unsigned long mempages)
if (!dentry_cache)
panic("Cannot create dentry cache");
+#if PAGE_SHIFT < 13
mempages >>= (13 - PAGE_SHIFT);
+#endif
mempages *= sizeof(struct list_head);
for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
;
@@ -1228,9 +1230,6 @@ static void __init dcache_init(unsigned long mempages)
/* SLAB cache for __getname() consumers */
kmem_cache_t *names_cachep;
-/* SLAB cache for files_struct structures */
-kmem_cache_t *files_cachep;
-
/* SLAB cache for file structures */
kmem_cache_t *filp_cachep;
@@ -1246,7 +1245,7 @@ void __init vfs_caches_init(unsigned long mempages)
sizeof(struct buffer_head), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!bh_cachep)
- panic("Cannot create buffer head SLAB cache\n");
+ panic("Cannot create buffer head SLAB cache");
names_cachep = kmem_cache_create("names_cache",
PAGE_SIZE, 0,
@@ -1254,12 +1253,6 @@ void __init vfs_caches_init(unsigned long mempages)
if (!names_cachep)
panic("Cannot create names SLAB cache");
- files_cachep = kmem_cache_create("files_cache",
- sizeof(struct files_struct), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (!files_cachep)
- panic("Cannot create files SLAB cache");
-
filp_cachep = kmem_cache_create("filp",
sizeof(struct file), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index ad28db63a..3ffb8275e 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -2439,14 +2439,14 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir)
case 0:
scan_dir_for_removable (parent);
err = (*filldir) (dirent, "..", 2, file->f_pos,
- file->f_dentry->d_parent->d_inode->i_ino);
+ file->f_dentry->d_parent->d_inode->i_ino, DT_DIR);
if (err == -EINVAL) break;
if (err < 0) return err;
file->f_pos++;
++stored;
/* Fall through */
case 1:
- err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino);
+ err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR);
if (err == -EINVAL) break;
if (err < 0) return err;
file->f_pos++;
@@ -2463,7 +2463,7 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir)
{
if ( IS_HIDDEN (de) ) continue;
err = (*filldir) (dirent, de->name, de->namelen,
- file->f_pos, de->inode.ino);
+ file->f_pos, de->inode.ino, de->mode >> 12);
if (err == -EINVAL) break;
if (err < 0) return err;
file->f_pos++;
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
index 06f6b3baa..dd696709f 100644
--- a/fs/devpts/root.c
+++ b/fs/devpts/root.c
@@ -52,12 +52,12 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi
switch(nr)
{
case 0:
- if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
@@ -66,7 +66,7 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi
int ptynr = nr - 2;
if ( sbi->inodes[ptynr] ) {
genptsname(numbuf, ptynr);
- if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_CHR) < 0 )
return 0;
}
filp->f_pos = ++nr;
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 2829a60eb..ac64b8aeb 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -78,7 +78,7 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
/* copy filename and data in dirslot */
- filldir(dirent, nameptr, namelen, filp->f_pos, inodenum);
+ filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN);
/* sanity check */
if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
diff --git a/fs/exec.c b/fs/exec.c
index 93aae1c7f..c0df3a68b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -402,7 +402,10 @@ static int exec_mmap(void)
if (mm) {
struct mm_struct *active_mm = current->active_mm;
- init_new_context(current, mm);
+ if (init_new_context(current, mm)) {
+ mmdrop(mm);
+ return -ENOMEM;
+ }
task_lock(current);
current->mm = mm;
current->active_mm = mm;
@@ -433,7 +436,7 @@ static inline int make_private_signals(void)
if (atomic_read(&current->sig->count) <= 1)
return 0;
- newsig = kmalloc(sizeof(*newsig), GFP_KERNEL);
+ newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL);
if (newsig == NULL)
return -ENOMEM;
spin_lock_init(&newsig->siglock);
@@ -457,7 +460,7 @@ static inline void release_old_signals(struct signal_struct * oldsig)
if (current->sig == oldsig)
return;
if (atomic_dec_and_test(&oldsig->count))
- kfree(oldsig);
+ kmem_cache_free(sigact_cachep, oldsig);
}
/*
@@ -467,22 +470,30 @@ static inline void release_old_signals(struct signal_struct * oldsig)
static inline void flush_old_files(struct files_struct * files)
{
- unsigned long j;
+ long j = -1;
- j = 0;
+ write_lock(&files->file_lock);
for (;;) {
unsigned long set, i;
+ j++;
i = j * __NFDBITS;
if (i >= files->max_fds || i >= files->max_fdset)
break;
- set = xchg(&files->close_on_exec->fds_bits[j], 0);
- j++;
+ set = files->close_on_exec->fds_bits[j];
+ if (!set)
+ continue;
+ files->close_on_exec->fds_bits[j] = 0;
+ write_unlock(&files->file_lock);
for ( ; set ; i++,set >>= 1) {
- if (set & 1)
+ if (set & 1) {
sys_close(i);
+ }
}
+ write_lock(&files->file_lock);
+
}
+ write_unlock(&files->file_lock);
}
int flush_old_exec(struct linux_binprm * bprm)
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 3a18b375c..cd49b5da6 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -20,6 +20,10 @@
#include <linux/fs.h>
+static unsigned char ext2_filetype_table[] = {
+ DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
+};
+
static int ext2_readdir(struct file *, void *, filldir_t);
struct file_operations ext2_dir_operations = {
@@ -152,10 +156,15 @@ revalidate:
* during the copy operation.
*/
unsigned long version = filp->f_version;
+ unsigned char d_type = DT_UNKNOWN;
+ if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE)
+ && de->file_type < EXT2_FT_MAX)
+ d_type = ext2_filetype_table[de->file_type];
error = filldir(dirent, de->name,
de->name_len,
- filp->f_pos, le32_to_cpu(de->inode));
+ filp->f_pos, le32_to_cpu(de->inode),
+ d_type);
if (error)
break;
if (version != filp->f_version)
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index bbb895285..5f7a643d7 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -313,7 +313,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
/* Fake . and .. for the root directory. */
if (inode->i_ino == MSDOS_ROOT_INO) {
while (cpos < 2) {
- if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0)
+ if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)
return 0;
cpos++;
filp->f_pos++;
@@ -466,7 +466,8 @@ ParseLong:
if (!long_slots||shortnames) {
if (both)
bufname[i] = '\0';
- if (filldir(dirent, bufname, i, *furrfu, inum) < 0)
+ if (filldir(dirent, bufname, i, *furrfu, inum,
+ (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
goto FillFailed;
} else {
char longname[275];
@@ -478,7 +479,8 @@ ParseLong:
memcpy(&longname[long_len+1], bufname, i);
long_len += i;
}
- if (filldir(dirent, longname, long_len, *furrfu, inum) < 0)
+ if (filldir(dirent, longname, long_len, *furrfu, inum,
+ (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
goto FillFailed;
}
@@ -508,7 +510,8 @@ static int vfat_ioctl_fill(
const char * name,
int name_len,
off_t offset,
- ino_t ino)
+ ino_t ino,
+ unsigned int d_type)
{
struct dirent *d1 = (struct dirent *)buf;
struct dirent *d2 = d1 + 1;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 35a5dbc7d..7a3bcefb8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -129,7 +129,7 @@ out_putf:
asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
{
int err = -EBADF;
- struct file * file;
+ struct file * file, *tofree;
struct files_struct * files = current->files;
write_lock(&files->file_lock);
@@ -144,31 +144,40 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
get_file(file); /* We are now finished with oldfd */
err = expand_files(files, newfd);
- if (err < 0) {
- write_unlock(&files->file_lock);
- fput(file);
- goto out;
- }
+ if (err < 0)
+ goto out_fput;
/* To avoid races with open() and dup(), we will mark the fd as
* in-use in the open-file bitmap throughout the entire dup2()
* process. This is quite safe: do_close() uses the fd array
* entry, not the bitmap, to decide what work needs to be
* done. --sct */
+ /* Doesn't work. open() might be there first. --AV */
+
+ /* Yes. It's a race. In user space. Nothing sane to do */
+ err = -EBUSY;
+ tofree = files->fd[newfd];
+ if (!tofree && FD_ISSET(newfd, files->open_fds))
+ goto out_fput;
+
+ files->fd[newfd] = file;
FD_SET(newfd, files->open_fds);
+ FD_CLR(newfd, files->close_on_exec);
write_unlock(&files->file_lock);
-
- do_close(files, newfd, 0);
- write_lock(&files->file_lock);
- allocate_fd(files, file, newfd);
+ if (tofree)
+ filp_close(tofree, files);
err = newfd;
-
out:
return err;
out_unlock:
write_unlock(&files->file_lock);
goto out;
+
+out_fput:
+ write_unlock(&files->file_lock);
+ fput(file);
+ goto out;
}
asmlinkage long sys_dup(unsigned int fildes)
@@ -209,16 +218,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
return 0;
}
-asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct file * filp;
- long err = -EBADF;
+static long do_fcntl(unsigned int fd, unsigned int cmd,
+ unsigned long arg, struct file * filp)
+{
+ long err = 0;
- filp = fget(fd);
- if (!filp)
- goto out;
- err = 0;
- lock_kernel();
switch (cmd) {
case F_DUPFD:
err = -EINVAL;
@@ -228,13 +232,10 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
}
break;
case F_GETFD:
- err = FD_ISSET(fd, current->files->close_on_exec);
+ err = get_close_on_exec(fd);
break;
case F_SETFD:
- if (arg&1)
- FD_SET(fd, current->files->close_on_exec);
- else
- FD_CLR(fd, current->files->close_on_exec);
+ set_close_on_exec(fd, arg&1);
break;
case F_GETFL:
err = filp->f_flags;
@@ -287,11 +288,60 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = sock_fcntl (filp, cmd, arg);
break;
}
+
+ return err;
+}
+
+asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct file * filp;
+ long err = -EBADF;
+
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ lock_kernel();
+ err = do_fcntl(fd, cmd, arg, filp);
+ unlock_kernel();
+
+ fput(filp);
+out:
+ return err;
+}
+
+#if BITS_PER_LONG == 32
+asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct file * filp;
+ long err;
+
+ err = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ lock_kernel();
+ switch (cmd) {
+ case F_GETLK64:
+ err = fcntl_getlk64(fd, (struct flock64 *) arg);
+ break;
+ case F_SETLK64:
+ err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
+ break;
+ case F_SETLKW64:
+ err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
+ break;
+ default:
+ err = do_fcntl(fd, cmd, arg, filp);
+ break;
+ }
unlock_kernel();
fput(filp);
out:
return err;
}
+#endif
/* Table to convert sigio signal codes into poll band bitmaps */
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
index bca53e087..9dfb4ab82 100644
--- a/fs/hfs/dir_cap.c
+++ b/fs/hfs/dir_cap.c
@@ -190,7 +190,7 @@ static int cap_readdir(struct file * filp,
if (filp->f_pos == 0) {
/* Entry 0 is for "." */
- if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
+ if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) {
return 0;
}
filp->f_pos = 1;
@@ -207,7 +207,7 @@ static int cap_readdir(struct file * filp,
}
if (filldir(dirent, DOT_DOT->Name,
- DOT_DOT_LEN, 1, ntohl(cnid))) {
+ DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
return 0;
}
filp->f_pos = 2;
@@ -234,7 +234,7 @@ static int cap_readdir(struct file * filp,
len = hfs_namein(dir, tmp_name,
&((struct hfs_cat_key *)brec.key)->CName);
if (filldir(dirent, tmp_name, len,
- filp->f_pos, ino)) {
+ filp->f_pos, ino, DT_UNKNOWN)) {
hfs_cat_close(entry, &brec);
return 0;
}
@@ -250,7 +250,8 @@ static int cap_readdir(struct file * filp,
/* In root dir last-2 entry is for ".rootinfo" */
if (filldir(dirent, DOT_ROOTINFO->Name,
DOT_ROOTINFO_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_CAP_FNDR)) {
+ ntohl(entry->cnid) | HFS_CAP_FNDR,
+ DT_UNKNOWN)) {
return 0;
}
}
@@ -262,7 +263,8 @@ static int cap_readdir(struct file * filp,
/* In normal dirs last-1 entry is for ".finderinfo" */
if (filldir(dirent, DOT_FINDERINFO->Name,
DOT_FINDERINFO_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_CAP_FDIR)) {
+ ntohl(entry->cnid) | HFS_CAP_FDIR,
+ DT_UNKNOWN)) {
return 0;
}
}
@@ -274,7 +276,8 @@ static int cap_readdir(struct file * filp,
/* In normal dirs last entry is for ".resource" */
if (filldir(dirent, DOT_RESOURCE->Name,
DOT_RESOURCE_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_CAP_RDIR)) {
+ ntohl(entry->cnid) | HFS_CAP_RDIR,
+ DT_UNKNOWN)) {
return 0;
}
}
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
index 3d613a8e3..8e39508fa 100644
--- a/fs/hfs/dir_dbl.c
+++ b/fs/hfs/dir_dbl.c
@@ -183,7 +183,8 @@ static int dbl_readdir(struct file * filp,
if (filp->f_pos == 0) {
/* Entry 0 is for "." */
- if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
+ if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
+ DT_DIR)) {
return 0;
}
filp->f_pos = 1;
@@ -192,7 +193,7 @@ static int dbl_readdir(struct file * filp,
if (filp->f_pos == 1) {
/* Entry 1 is for ".." */
if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1,
- hfs_get_hl(entry->key.ParID))) {
+ hfs_get_hl(entry->key.ParID), DT_DIR)) {
return 0;
}
filp->f_pos = 2;
@@ -229,7 +230,8 @@ static int dbl_readdir(struct file * filp,
&((struct hfs_cat_key *)brec.key)->CName);
}
- if (filldir(dirent, tmp_name, len, filp->f_pos, ino)) {
+ if (filldir(dirent, tmp_name, len, filp->f_pos, ino,
+ DT_UNKNOWN)) {
hfs_cat_close(entry, &brec);
return 0;
}
@@ -243,7 +245,8 @@ static int dbl_readdir(struct file * filp,
/* In root dir last entry is for "%RootInfo" */
if (filldir(dirent, PCNT_ROOTINFO->Name,
PCNT_ROOTINFO_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_DBL_HDR)) {
+ ntohl(entry->cnid) | HFS_DBL_HDR,
+ DT_UNKNOWN)) {
return 0;
}
}
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
index 992a94b67..4d050e698 100644
--- a/fs/hfs/dir_nat.c
+++ b/fs/hfs/dir_nat.c
@@ -191,7 +191,8 @@ static int nat_readdir(struct file * filp,
if (filp->f_pos == 0) {
/* Entry 0 is for "." */
- if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) {
+ if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
+ DT_DIR)) {
return 0;
}
filp->f_pos = 1;
@@ -208,7 +209,7 @@ static int nat_readdir(struct file * filp,
}
if (filldir(dirent, DOT_DOT->Name,
- DOT_DOT_LEN, 1, ntohl(cnid))) {
+ DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
return 0;
}
filp->f_pos = 2;
@@ -235,7 +236,7 @@ static int nat_readdir(struct file * filp,
len = hfs_namein(dir, tmp_name,
&((struct hfs_cat_key *)brec.key)->CName);
if (filldir(dirent, tmp_name, len,
- filp->f_pos, ino)) {
+ filp->f_pos, ino, DT_UNKNOWN)) {
hfs_cat_close(entry, &brec);
return 0;
}
@@ -250,14 +251,16 @@ static int nat_readdir(struct file * filp,
/* In normal dirs entry 2 is for ".AppleDouble" */
if (filldir(dirent, DOT_APPLEDOUBLE->Name,
DOT_APPLEDOUBLE_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_NAT_HDIR)) {
+ ntohl(entry->cnid) | HFS_NAT_HDIR,
+ DT_UNKNOWN)) {
return 0;
}
} else if (type == HFS_NAT_HDIR) {
/* In .AppleDouble entry 2 is for ".Parent" */
if (filldir(dirent, DOT_PARENT->Name,
DOT_PARENT_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_NAT_HDR)) {
+ ntohl(entry->cnid) | HFS_NAT_HDR,
+ DT_UNKNOWN)) {
return 0;
}
}
@@ -270,7 +273,8 @@ static int nat_readdir(struct file * filp,
(type == HFS_NAT_HDIR)) {
if (filldir(dirent, ROOTINFO->Name,
ROOTINFO_LEN, filp->f_pos,
- ntohl(entry->cnid) | HFS_NAT_HDR)) {
+ ntohl(entry->cnid) | HFS_NAT_HDR,
+ DT_UNKNOWN)) {
return 0;
}
}
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 15db6e936..40e432163 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -108,14 +108,14 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
return 0;
}
if (filp->f_pos == 0) {
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) {
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
hpfs_unlock_inode(inode);
return 0;
}
filp->f_pos = 11;
}
if (filp->f_pos == 11) {
- if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) {
+ if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir, DT_DIR) < 0) {
hpfs_unlock_inode(inode);
return 0;
}
@@ -144,7 +144,7 @@ int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto again;
}
tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
- if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode) < 0) {
+ if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) {
filp->f_pos = old_pos;
if (tempname != (char *)de->name) kfree(tempname);
hpfs_brelse4(&qbh);
diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h
index f13f2fa7e..4d342db5f 100644
--- a/fs/hpfs/hpfs.h
+++ b/fs/hpfs/hpfs.h
@@ -187,7 +187,9 @@ struct code_page_directory
in data block */
secno code_page_data; /* sector number of a code_page_data
containing c.p. array */
- unsigned index; /* index in c.p. array in that sector*/
+ unsigned short index; /* index in c.p. array in that sector*/
+ unsigned short unknown; /* some unknown value; usually 0;
+ 2 in Japanese version */
} array[31]; /* unknown length */
};
@@ -207,7 +209,7 @@ struct code_page_data
struct {
unsigned short ix; /* index */
unsigned short code_page_number; /* code page number */
- unsigned short zero1;
+ unsigned short unknown; /* the same as in cp directory */
unsigned char map[128]; /* upcase table for chars 80..ff */
unsigned short zero2;
} code_page[3];
diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c
index a0e0feada..290844b4d 100644
--- a/fs/hpfs/map.c
+++ b/fs/hpfs/map.c
@@ -59,6 +59,11 @@ char *hpfs_load_code_page(struct super_block *s, secno cps)
cpds = cp->array[0].code_page_data;
cpi = cp->array[0].index;
brelse(bh);
+
+ if (cpi >= 3) {
+ printk("HPFS: Code page index out of array\n");
+ return NULL;
+ }
if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL;
if ((unsigned)cpd->offs[cpi] > 0x178) {
diff --git a/fs/inode.c b/fs/inode.c
index 455c4af6e..2199d6888 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -771,6 +771,7 @@ void iput(struct inode *inode)
list_del(&inode->i_list);
INIT_LIST_HEAD(&inode->i_list);
inode->i_state|=I_FREEING;
+ inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
if (inode->i_data.nrpages)
@@ -799,11 +800,11 @@ void iput(struct inode *inode)
list_del(&inode->i_list);
INIT_LIST_HEAD(&inode->i_list);
inode->i_state|=I_FREEING;
+ inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
clear_inode(inode);
}
}
- inodes_stat.nr_inodes--;
destroy_inode(inode);
}
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index f02d766bd..21af77a3a 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -58,11 +58,11 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
lock_kernel();
switch (cmd) {
case FIOCLEX:
- FD_SET(fd, current->files->close_on_exec);
+ set_close_on_exec(fd, 1);
break;
case FIONCLEX:
- FD_CLR(fd, current->files->close_on_exec);
+ set_close_on_exec(fd, 0);
break;
case FIONBIO:
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 1b99acb19..41b201767 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -202,7 +202,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* Handle the case of the '.' directory */
if (de->name_len[0] == 1 && de->name[0] == 0) {
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
break;
filp->f_pos += de_len;
continue;
@@ -213,7 +213,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
- if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
+ if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
break;
filp->f_pos += de_len;
continue;
@@ -258,7 +258,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
}
}
if (len > 0) {
- if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
+ if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
break;
}
filp->f_pos += de_len;
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 9ea2223d3..266e7bf64 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -10,7 +10,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: inode-v23.c,v 1.33 2000/08/09 15:59:06 dwmw2 Exp $
+ * $Id: inode-v23.c,v 1.34 2000/08/10 08:58:00 dwmw2 Exp $
*
*
* Ported to Linux 2.3.x and MTD:
@@ -44,7 +44,6 @@
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
-#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/stat.h>
#include <linux/blkdev.h>
@@ -350,7 +349,7 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
inode->i_mtime = raw_inode->mtime;
inode->i_ctime = raw_inode->ctime;
inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = (raw_inode->dsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
inode->i_version = 0;
inode->i_flags = sb->s_flags;
inode->u.generic_ip = (void *)jffs_find_file(c, raw_inode->ino);
@@ -558,7 +557,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
D2(printk("jffs_readdir(): inode: 0x%p, filp: 0x%p\n", inode, filp));
if (filp->f_pos == 0) {
D3(printk("jffs_readdir(): \".\" %lu\n", inode->i_ino));
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) {
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
return 0;
}
filp->f_pos = 1;
@@ -572,7 +571,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
inode->u.generic_ip)->pino;
}
D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
- if (filldir(dirent, "..", 2, filp->f_pos, ddino) < 0)
+ if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0)
return 0;
filp->f_pos++;
}
@@ -584,7 +583,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
D3(printk("jffs_readdir(): \"%s\" ino: %u\n",
(f->name ? f->name : ""), f->ino));
if (filldir(dirent, f->name, f->nsize,
- filp->f_pos , f->ino) < 0)
+ filp->f_pos , f->ino, DT_UNKNOWN) < 0)
return 0;
filp->f_pos++;
}
@@ -1571,7 +1570,7 @@ jffs_read_inode(struct inode *inode)
inode->i_mtime = f->mtime;
inode->i_ctime = f->ctime;
inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
if (S_ISREG(inode->i_mode)) {
inode->i_op = &jffs_file_inode_operations;
inode->i_fop = &jffs_file_operations;
diff --git a/fs/locks.c b/fs/locks.c
index c1054c341..ae4cc8069 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -103,6 +103,11 @@
*
* Fixed /proc/locks interface so that we can't overrun the buffer we are handed.
* Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997.
+ *
+ * Use slab allocator instead of kmalloc/kfree.
+ * Use generic list implementation from <linux/list.h>.
+ * Sped up posix_locks_deadlock by only considering blocked locks.
+ * Matthew Wilcox <willy@thepuffingroup.com>, March, 2000.
*/
#include <linux/malloc.h>
@@ -205,8 +210,58 @@ static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
* style lock.
*/
-static int posix_make_lock(struct file *filp, struct file_lock *fl,
- struct flock *l)
+static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
+ struct flock *l)
+{
+ loff_t start;
+
+ switch (l->l_whence) {
+ case 0: /*SEEK_SET*/
+ start = 0;
+ break;
+ case 1: /*SEEK_CUR*/
+ start = filp->f_pos;
+ break;
+ case 2: /*SEEK_END*/
+ start = filp->f_dentry->d_inode->i_size;
+ break;
+ default:
+ return (0);
+ }
+
+ if (((start += l->l_start) < 0) || (l->l_len < 0))
+ return (0);
+ fl->fl_end = start + l->l_len - 1;
+ if (l->l_len > 0 && fl->fl_end < 0)
+ return (0);
+ fl->fl_start = start; /* we record the absolute position */
+ if (l->l_len == 0)
+ fl->fl_end = OFFSET_MAX;
+
+ fl->fl_owner = current->files;
+ fl->fl_pid = current->pid;
+ fl->fl_file = filp;
+ fl->fl_flags = FL_POSIX;
+ fl->fl_notify = NULL;
+ fl->fl_insert = NULL;
+ fl->fl_remove = NULL;
+
+ switch (l->l_type) {
+ case F_RDLCK:
+ case F_WRLCK:
+ case F_UNLCK:
+ fl->fl_type = l->l_type;
+ break;
+ default:
+ return (0);
+ }
+
+ return (1);
+}
+
+#if BITS_PER_LONG == 32
+static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
+ struct flock64 *l)
{
loff_t start;
@@ -253,6 +308,7 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
return (1);
}
+#endif
/* Check if two locks overlap each other.
*/
@@ -300,8 +356,8 @@ static void locks_insert_block(struct file_lock *blocker,
locks_delete_block(waiter);
}
list_add_tail(&waiter->fl_block, &blocker->fl_block);
-// list_add(&waiter->fl_link, &blocked_list);
-// waiter->fl_next = blocker;
+ list_add(&waiter->fl_link, &blocked_list);
+ waiter->fl_next = blocker;
}
/* Wake up processes blocked waiting for blocker.
@@ -460,34 +516,27 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
struct list_head *tmp;
- void *caller_owner, *blocked_owner;
+ fl_owner_t caller_owner, blocked_owner;
unsigned int caller_pid, blocked_pid;
caller_owner = caller_fl->fl_owner;
caller_pid = caller_fl->fl_pid;
blocked_owner = block_fl->fl_owner;
blocked_pid = block_fl->fl_pid;
+ tmp = blocked_list.next;
next_task:
if (caller_owner == blocked_owner && caller_pid == blocked_pid)
return 1;
- list_for_each(tmp, &file_lock_list) {
- struct list_head *btmp;
+ while (tmp != &blocked_list) {
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
- if (fl->fl_owner == NULL || list_empty(&fl->fl_block))
- continue;
- list_for_each(btmp, &fl->fl_block) {
- struct file_lock *bfl = list_entry(tmp, struct file_lock, fl_block);
- if (bfl->fl_owner == blocked_owner &&
- bfl->fl_pid == blocked_pid) {
- if (fl->fl_owner == caller_owner &&
- fl->fl_pid == caller_pid) {
- return (1);
- }
- blocked_owner = fl->fl_owner;
- blocked_pid = fl->fl_pid;
- goto next_task;
- }
+ tmp = tmp->next;
+ if ((fl->fl_owner == blocked_owner)
+ && (fl->fl_pid == blocked_pid)) {
+ fl = fl->fl_next;
+ blocked_owner = fl->fl_owner;
+ blocked_pid = fl->fl_pid;
+ goto next_task;
}
}
return 0;
@@ -816,13 +865,12 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
if (right) {
if (left == right) {
/* The new lock breaks the old one in two pieces,
- * so we have to use the second new lock (in this
- * case, even F_UNLCK may fail!).
+ * so we have to use the second new lock.
*/
- locks_copy_lock(new_fl2, right);
- locks_insert_lock(before, left);
left = new_fl2;
new_fl2 = NULL;
+ locks_copy_lock(left, right);
+ locks_insert_lock(before, left);
}
right->fl_start = caller->fl_end + 1;
locks_wake_up_blocks(right, 0);
@@ -909,7 +957,8 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
if (!filp)
goto out;
- if (!posix_make_lock(filp, file_lock, &flock))
+ error = -EINVAL;
+ if (!flock_to_posix_lock(filp, file_lock, &flock))
goto out_putf;
if (filp->f_op->lock) {
@@ -928,6 +977,18 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
flock.l_type = F_UNLCK;
if (fl != NULL) {
flock.l_pid = fl->fl_pid;
+#if BITS_PER_LONG == 32
+ /*
+ * Make sure we can represent the posix lock via
+ * legacy 32bit flock.
+ */
+ error = -EOVERFLOW;
+ if (fl->fl_start > OFFT_OFFSET_MAX)
+ goto out_putf;
+ if ((fl->fl_end != OFFSET_MAX)
+ && (fl->fl_end > OFFT_OFFSET_MAX))
+ goto out_putf;
+#endif
flock.l_start = fl->fl_start;
flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
fl->fl_end - fl->fl_start + 1;
@@ -993,7 +1054,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
}
error = -EINVAL;
- if (!posix_make_lock(filp, file_lock, &flock))
+ if (!flock_to_posix_lock(filp, file_lock, &flock))
goto out_putf;
error = -EBADF;
@@ -1044,6 +1105,151 @@ out:
return error;
}
+#if BITS_PER_LONG == 32
+/* Report the first existing lock that would conflict with l.
+ * This implements the F_GETLK command of fcntl().
+ */
+int fcntl_getlk64(unsigned int fd, struct flock64 *l)
+{
+ struct file *filp;
+ struct file_lock *fl, *file_lock = locks_alloc_lock();
+ struct flock64 flock;
+ int error;
+
+ error = -EFAULT;
+ if (copy_from_user(&flock, l, sizeof(flock)))
+ goto out;
+ error = -EINVAL;
+ if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
+ goto out;
+
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ error = -EINVAL;
+ if (!flock64_to_posix_lock(filp, file_lock, &flock))
+ goto out_putf;
+
+ if (filp->f_op->lock) {
+ error = filp->f_op->lock(filp, F_GETLK, file_lock);
+ if (error < 0)
+ goto out_putf;
+ else if (error == LOCK_USE_CLNT)
+ /* Bypass for NFS with no locking - 2.0.36 compat */
+ fl = posix_test_lock(filp, file_lock);
+ else
+ fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock);
+ } else {
+ fl = posix_test_lock(filp, file_lock);
+ }
+
+ flock.l_type = F_UNLCK;
+ if (fl != NULL) {
+ flock.l_pid = fl->fl_pid;
+ flock.l_start = fl->fl_start;
+ flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
+ fl->fl_end - fl->fl_start + 1;
+ flock.l_whence = 0;
+ flock.l_type = fl->fl_type;
+ }
+ error = -EFAULT;
+ if (!copy_to_user(l, &flock, sizeof(flock)))
+ error = 0;
+
+out_putf:
+ fput(filp);
+out:
+ locks_free_lock(file_lock);
+ return error;
+}
+
+/* Apply the lock described by l to an open file descriptor.
+ * This implements both the F_SETLK and F_SETLKW commands of fcntl().
+ */
+int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
+{
+ struct file *filp;
+ struct file_lock *file_lock = locks_alloc_lock();
+ struct flock64 flock;
+ struct inode *inode;
+ int error;
+
+ /*
+ * This might block, so we do it before checking the inode.
+ */
+ error = -EFAULT;
+ if (copy_from_user(&flock, l, sizeof(flock)))
+ goto out;
+
+ /* Get arguments and validate them ...
+ */
+
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ error = -EINVAL;
+ inode = filp->f_dentry->d_inode;
+
+ /* Don't allow mandatory locks on files that may be memory mapped
+ * and shared.
+ */
+ if (IS_MANDLOCK(inode) &&
+ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+ struct vm_area_struct *vma;
+ struct address_space *mapping = inode->i_mapping;
+ spin_lock(&mapping->i_shared_lock);
+ for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
+ if (!(vma->vm_flags & VM_MAYSHARE))
+ continue;
+ spin_unlock(&mapping->i_shared_lock);
+ error = -EAGAIN;
+ goto out_putf;
+ }
+ spin_unlock(&mapping->i_shared_lock);
+ }
+
+ error = -EINVAL;
+ if (!flock64_to_posix_lock(filp, file_lock, &flock))
+ goto out_putf;
+
+ error = -EBADF;
+ switch (flock.l_type) {
+ case F_RDLCK:
+ if (!(filp->f_mode & FMODE_READ))
+ goto out_putf;
+ break;
+ case F_WRLCK:
+ if (!(filp->f_mode & FMODE_WRITE))
+ goto out_putf;
+ break;
+ case F_UNLCK:
+ break;
+ case F_SHLCK:
+ case F_EXLCK:
+ default:
+ error = -EINVAL;
+ goto out_putf;
+ }
+
+ if (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);
+
+out_putf:
+ fput(filp);
+out:
+ locks_free_lock(file_lock);
+ return error;
+}
+#endif /* BITS_PER_LONG == 32 */
+
/*
* This function is called when the file is being removed
* from the task's fd array.
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 6443f05ed..1cc918910 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -43,7 +43,7 @@ static int minix_readdir(struct file * filp,
de = (struct minix_dir_entry *) (offset + bh->b_data);
if (de->inode) {
int size = strnlen(de->name, info->s_namelen);
- if (filldir(dirent, de->name, size, filp->f_pos, de->inode) < 0) {
+ if (filldir(dirent, de->name, size, filp->f_pos, de->inode, DT_UNKNOWN) < 0) {
brelse(bh);
return 0;
}
diff --git a/fs/namei.c b/fs/namei.c
index 97d9e2d22..75ffc6ef0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1690,7 +1690,8 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
triple_up(&old_dir->i_zombie,
&new_dir->i_zombie,
&target->i_zombie);
- d_rehash(new_dentry);
+ if (d_unhashed(new_dentry))
+ d_rehash(new_dentry);
dput(new_dentry);
} else
double_up(&old_dir->i_zombie,
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 8cb5a5c06..1c0f13e3b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -446,13 +446,13 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
result = 0;
if (filp->f_pos == 0) {
- if (filldir(dirent, ".", 1, 0, inode->i_ino))
+ if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
goto out;
filp->f_pos = 1;
}
if (filp->f_pos == 1) {
if (filldir(dirent, "..", 2, 1,
- dentry->d_parent->d_inode->i_ino))
+ dentry->d_parent->d_inode->i_ino, DT_DIR))
goto out;
filp->f_pos = 2;
}
@@ -503,7 +503,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto invalid_cache;
res = filldir(dirent, dent->d_name.name,
dent->d_name.len, filp->f_pos,
- dent->d_inode->i_ino);
+ dent->d_inode->i_ino, DT_UNKNOWN);
dput(dent);
if (res)
goto finished;
@@ -650,7 +650,7 @@ end_advance:
if (!ino)
ino = iunique(inode->i_sb, 2);
ctl.filled = filldir(dirent, qname.name, qname.len,
- filp->f_pos, ino);
+ filp->f_pos, ino, DT_UNKNOWN);
if (!ctl.filled)
filp->f_pos += 1;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 5c5c3a95f..11b8e5d79 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -264,7 +264,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
* retrieving the current dirent on the server */
fileid = nfs_fileid_to_ino_t(entry->ino);
res = filldir(dirent, entry->name, entry->len,
- entry->prev_cookie, fileid);
+ entry->prev_cookie, fileid, DT_UNKNOWN);
if (res < 0)
break;
file->f_pos = desc->target = entry->cookie;
@@ -890,9 +890,8 @@ static int nfs_safe_remove(struct dentry *dentry)
struct inode *inode = dentry->d_inode;
int error = -EBUSY, rehash = 0;
- dfprintk(VFS, "NFS: safe_remove(%s/%s, %ld)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- inode->i_ino);
+ dfprintk(VFS, "NFS: safe_remove(%s/%s)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
/*
* Unhash the dentry while we remove the file ...
@@ -910,7 +909,8 @@ static int nfs_safe_remove(struct dentry *dentry)
goto out;
}
nfs_zap_caches(dir_i);
- NFS_CACHEINV(inode);
+ if (inode)
+ NFS_CACHEINV(inode);
error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name);
if (error < 0)
goto out;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index db7c110e5..5e7ced09e 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -402,9 +402,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
if (data->wsize == 0)
server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
- server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
- if (server->dtsize > PAGE_CACHE_SIZE)
- server->dtsize = PAGE_CACHE_SIZE;
/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
if (!fsinfo.bsize)
fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
@@ -434,6 +431,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->wsize = server->wpages << PAGE_CACHE_SHIFT;
}
+ server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+ if (server->dtsize > PAGE_CACHE_SIZE)
+ server->dtsize = PAGE_CACHE_SIZE;
+ if (server->dtsize > server->rsize)
+ server->dtsize = server->rsize;
+
maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
if (server->namelen == 0 || server->namelen > maxlen)
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 373d7296c..574c26a15 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -321,12 +321,8 @@ nfs_proc_readdir(struct file *file, __u64 cookie, void *entry,
struct nfs_readdirargs arg;
struct nfs_readdirres res;
struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred };
- struct nfs_server *server = NFS_DSERVER(dir);
int status;
- if (server->rsize < size)
- size = server->rsize;
-
arg.fh = NFS_FH(dir);
arg.cookie = cookie;
arg.buffer = entry;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index cb97c40bc..a5bda60ba 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1291,7 +1291,7 @@ nfs_writeback_done(struct rpc_task *task)
static void
nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
{
- struct nfs_page *req;
+ struct nfs_page *first, *last;
struct dentry *dentry;
struct inode *inode;
loff_t start, end, len;
@@ -1299,32 +1299,28 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
- end = 0;
- start = ~0;
- req = nfs_list_entry(head->next);
- dentry = req->wb_dentry;
- data->dentry = dentry;
- data->cred = req->wb_cred;
+ list_splice(head, &data->pages);
+ 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;
- while (!list_empty(head)) {
- struct nfs_page *req;
- loff_t rqstart, rqend;
- req = nfs_list_entry(head->next);
- nfs_list_remove_request(req);
- nfs_list_add_request(req, &data->pages);
- rqstart = page_offset(req->wb_page) + req->wb_offset;
- rqend = rqstart + req->wb_bytes;
- if (rqstart < start)
- start = rqstart;
- if (rqend > end)
- end = rqend;
- }
- data->args.fh = NFS_FH(dentry);
- data->args.offset = start;
+
+ /*
+ * Determine the offset range of requests in the COMMIT call.
+ * We rely on the fact that data->pages is an ordered list...
+ */
+ start = page_offset(first->wb_page) + first->wb_offset;
+ end = page_offset(last->wb_page) + (last->wb_offset + last->wb_bytes);
len = end - start;
/* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */
- if (end >= inode->i_size || len > (~((u32)0) >> 1))
+ if (end >= inode->i_size || len < 0 || len > (~((u32)0) >> 1))
len = 0;
+
+ data->dentry = dentry;
+ data->cred = first->wb_cred;
+ data->args.fh = NFS_FH(dentry);
+ data->args.offset = start;
data->res.count = data->args.count = (u32)len;
data->res.fattr = &data->fattr;
data->res.verf = &data->verf;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 948566a6e..308db4cd5 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -669,7 +669,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
static int
encode_entry(struct readdir_cd *cd, const char *name,
- int namlen, off_t offset, ino_t ino, int plus)
+ int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
{
u32 *p = cd->buffer;
int buflen, slen, elen;
@@ -747,16 +747,16 @@ noexec:
int
nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
- int namlen, off_t offset, ino_t ino)
+ int namlen, off_t offset, ino_t ino, unsigned int d_type)
{
- return encode_entry(cd, name, namlen, offset, ino, 0);
+ return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
}
int
nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
- int namlen, off_t offset, ino_t ino)
+ int namlen, off_t offset, ino_t ino, unsigned int d_type)
{
- return encode_entry(cd, name, namlen, offset, ino, 1);
+ return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
}
/* FSSTAT */
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 52a0348c1..d1b6306db 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -41,7 +41,7 @@ struct nfsd_getdents_callback {
* the name matching the specified inode number.
*/
static int filldir_one(void * __buf, const char * name, int len,
- off_t pos, ino_t ino)
+ off_t pos, ino_t ino, unsigned int d_type)
{
struct nfsd_getdents_callback *buf = __buf;
struct qstr *qs = buf->name;
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 7b9546d93..9127e0869 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -390,7 +390,7 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
int
nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
- int namlen, off_t offset, ino_t ino)
+ int namlen, off_t offset, ino_t ino, unsigned int d_type)
{
u32 *p = cd->buffer;
int buflen, slen;
diff --git a/fs/nls/Config.in b/fs/nls/Config.in
index c33e9d6b8..5c9754aca 100644
--- a/fs/nls/Config.in
+++ b/fs/nls/Config.in
@@ -4,7 +4,8 @@
# msdos and Joliet want NLS
if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
- -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then
+ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
+ -o "$CONFIG_SMB_FS" != "n" ]; then
define_bool CONFIG_NLS y
else
define_bool CONFIG_NLS n
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 0d372ddfa..c99e81e6a 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -200,7 +200,7 @@ static int ntfs_printcb(ntfs_u8 *entry,void *param)
/* filldir expects an off_t rather than an loff_t.
Hope we don't have more than 65535 index records */
error=nf->filldir(nf->dirent,nf->name,nf->namelen,
- (nf->ph<<16)|nf->pl,inum);
+ (nf->ph<<16)|nf->pl,inum,DT_UNKNOWN);
ntfs_free(nf->name);
/* Linux filldir errors are negative, other errors positive */
return error;
@@ -226,11 +226,11 @@ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir)
if(cb.ph==0xFFFF){
/* FIXME: Maybe we can return those with the previous call */
switch(cb.pl){
- case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino);
+ case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino,DT_DIR);
filp->f_pos=0xFFFF0001;
return 0;
/* FIXME: parent directory */
- case 1: filldir(dirent,"..",2,filp->f_pos,0);
+ case 1: filldir(dirent,"..",2,filp->f_pos,0,DT_DIR);
filp->f_pos=0xFFFF0002;
return 0;
}
diff --git a/fs/open.c b/fs/open.c
index c42b15a41..0f1787025 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -680,7 +680,7 @@ int get_unused_fd(void)
repeat:
fd = find_next_zero_bit(files->open_fds,
- current->files->max_fdset,
+ files->max_fdset,
files->next_fd);
/*
@@ -691,7 +691,7 @@ repeat:
goto out;
/* Do we need to expand the fdset array? */
- if (fd >= current->files->max_fdset) {
+ if (fd >= files->max_fdset) {
error = expand_fdset(files, fd);
if (!error) {
error = -EMFILE;
@@ -799,36 +799,27 @@ int filp_close(struct file *filp, fl_owner_t id)
* Careful here! We test whether the file pointer is NULL before
* releasing the fd. This ensures that one clone task can't release
* an fd while another clone is opening it.
- *
- * The "release" argument tells us whether or not to mark the fd as free
- * or not in the open-files bitmap. dup2 uses this to retain the fd
- * without races.
*/
-int do_close(struct files_struct *files, unsigned int fd, int release)
+asmlinkage long sys_close(unsigned int fd)
{
- int error;
struct file * filp;
+ struct files_struct *files = current->files;
- error = -EBADF;
write_lock(&files->file_lock);
- filp = frip(files, fd);
+ if (fd >= files->max_fds)
+ goto out_unlock;
+ filp = files->fd[fd];
if (!filp)
goto out_unlock;
+ files->fd[fd] = NULL;
FD_CLR(fd, files->close_on_exec);
- if (release)
- __put_unused_fd(files, fd);
+ __put_unused_fd(files, fd);
write_unlock(&files->file_lock);
- error = filp_close(filp, files);
-out:
- return error;
+ return filp_close(filp, files);
+
out_unlock:
write_unlock(&files->file_lock);
- goto out;
-}
-
-asmlinkage long sys_close(unsigned int fd)
-{
- return do_close(current->files, fd, 1);
+ return -EBADF;
}
/*
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index abd6ec28e..e264dd3d3 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.12 2000/07/13 08:06:42 davem Exp $
+/* $Id: inode.c,v 1.13 2000/08/12 13:25:46 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
@@ -757,14 +757,14 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld
i = filp->f_pos;
switch (i) {
case 0:
- if (filldir(dirent, ".", 1, i, ino) < 0) return 0;
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) return 0;
i++;
filp->f_pos++;
/* fall thru */
case 1:
if (filldir(dirent, "..", 2, i,
(NODE(ino).parent == 0xffff) ?
- OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent)) < 0)
+ OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
@@ -780,14 +780,14 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld
if (prom_getname (nodes[node].node, buffer, 128) < 0)
return 0;
if (filldir(dirent, buffer, strlen(buffer),
- filp->f_pos, NODE2INO(node)) < 0)
+ filp->f_pos, NODE2INO(node), DT_DIR) < 0)
return 0;
filp->f_pos++;
node = nodes[node].next;
}
j = NODEP2INO(NODE(ino).first_prop);
if (!i) {
- if (filldir(dirent, ".node", 5, filp->f_pos, j) < 0)
+ if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0)
return 0;
filp->f_pos++;
} else
@@ -798,7 +798,7 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld
if (alias_names [i]) {
if (filldir (dirent, alias_names [i],
strlen (alias_names [i]),
- filp->f_pos, j) < 0) return 0;
+ filp->f_pos, j, DT_REG) < 0) return 0;
filp->f_pos++;
}
}
@@ -810,7 +810,7 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld
if (i) i--;
else {
if (filldir(dirent, p, strlen(p),
- filp->f_pos, j) < 0)
+ filp->f_pos, j, DT_REG) < 0)
return 0;
filp->f_pos++;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index ef51478a1..8745b6f88 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -545,9 +545,9 @@ int do_pipe(int *fd)
this.len = strlen(name);
this.hash = inode->i_ino; /* will go */
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
- dentry->d_op = &pipefs_dentry_operations;
if (!dentry)
goto close_f12_inode_i_j;
+ dentry->d_op = &pipefs_dentry_operations;
d_add(dentry, inode);
f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
f1->f_dentry = f2->f_dentry = dget(dentry);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 9137fc765..4bcb92d31 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -301,12 +301,11 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
{
unsigned long vsize, eip, esp, wchan;
long priority, nice;
- int tty_pgrp;
+ int tty_pgrp = -1, tty_nr = 0;
sigset_t sigign, sigcatch;
char state;
int res;
pid_t ppid;
- int tty_nr;
struct mm_struct *mm;
state = *get_task_state(task);
@@ -315,6 +314,10 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
mm = task->mm;
if(mm)
atomic_inc(&mm->mm_users);
+ if (task->tty) {
+ tty_pgrp = task->tty->pgrp;
+ tty_nr = kdev_t_to_nr(task->tty->device);
+ }
task_unlock(task);
if (mm) {
struct vm_area_struct *vma;
@@ -333,14 +336,6 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
collect_sigign_sigcatch(task, &sigign, &sigcatch);
- task_lock(task);
- if (task->tty)
- tty_pgrp = task->tty->pgrp;
- else
- tty_pgrp = -1;
- tty_nr = task->tty ? kdev_t_to_nr(task->tty->device) : 0;
- task_unlock(task);
-
/* scale priority and nice values from timeslices to -20..20 */
/* to make it look like a "normal" Unix priority/nice value */
priority = task->counter;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 23151f3d9..7625e4d5a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -522,12 +522,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
fd = filp->f_pos;
switch (fd) {
case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
goto out;
filp->f_pos++;
case 1:
ino = fake_ino(pid, PROC_PID_INO);
- if (filldir(dirent, "..", 2, 1, ino) < 0)
+ if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
goto out;
filp->f_pos++;
default:
@@ -555,7 +555,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
} while (i);
ino = fake_ino(pid, PROC_PID_FD_DIR + fd);
- if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
+ if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0)
break;
}
put_files_struct(files);
@@ -578,13 +578,13 @@ static int proc_base_readdir(struct file * filp,
i = filp->f_pos;
switch (i) {
case 0:
- if (filldir(dirent, ".", 1, i, inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, i, inode->i_ino, DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, i, PROC_ROOT_INO) < 0)
+ if (filldir(dirent, "..", 2, i, PROC_ROOT_INO, DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
@@ -595,7 +595,8 @@ static int proc_base_readdir(struct file * filp,
return 1;
p = base_stuff + i;
while (p->name) {
- if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type)) < 0)
+ if (filldir(dirent, p->name, p->len, filp->f_pos,
+ fake_ino(pid, p->type), p->mode >> 12) < 0)
return 0;
filp->f_pos++;
p++;
@@ -1007,7 +1008,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
if (!nr) {
ino_t ino = fake_ino(0,PROC_PID_INO);
- if (filldir(dirent, "self", 4, filp->f_pos, ino) < 0)
+ if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
return 0;
filp->f_pos++;
nr++;
@@ -1022,7 +1023,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
do buf[--j] = '0' + (pid % 10); while (pid/=10);
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
+ if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0)
break;
filp->f_pos++;
}
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 9c7270070..ba2f88e9f 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -294,15 +294,15 @@ int proc_readdir(struct file * filp,
i = filp->f_pos;
switch (i) {
case 0:
- if (filldir(dirent, ".", 1, i, ino) < 0)
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
/* fall through */
case 1:
if (filldir(dirent, "..", 2, i,
- filp->f_dentry->d_parent->d_inode->i_ino
- ) < 0)
+ filp->f_dentry->d_parent->d_inode->i_ino,
+ DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
@@ -320,7 +320,8 @@ int proc_readdir(struct file * filp,
}
do {
- if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos,
+ de->low_ino, de->mode >> 12) < 0)
return 0;
filp->f_pos++;
de = de->next;
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 4b146945a..ac5d09b91 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -62,7 +62,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
QNX4_INODES_PER_BLOCK +
le->dl_inode_ndx;
}
- if (filldir(dirent, de->di_fname, size, filp->f_pos, ino) < 0) {
+ if (filldir(dirent, de->di_fname, size, filp->f_pos, ino, DT_UNKNOWN) < 0) {
brelse(bh);
return 0;
}
diff --git a/fs/readdir.c b/fs/readdir.c
index e1e90c113..cd8f7ad3d 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -13,9 +13,7 @@
#include <asm/uaccess.h>
-int vfs_readdir(struct file *file,
- int (*filler)(void *,const char *,int,off_t,ino_t),
- void *buf)
+int vfs_readdir(struct file *file, filldir_t filler, void *buf)
{
struct inode *inode = file->f_dentry->d_inode;
int res = -ENOTDIR;
@@ -49,13 +47,13 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
i = filp->f_pos;
switch (i) {
case 0:
- if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0)
+ if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
break;
i++;
filp->f_pos++;
/* fallthrough */
case 1:
- if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0)
+ if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
break;
i++;
filp->f_pos++;
@@ -83,7 +81,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
if (!list_empty(&de->d_hash) && de->d_inode) {
spin_unlock(&dcache_lock);
- if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0)
+ if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0)
break;
spin_lock(&dcache_lock);
}
@@ -124,7 +122,8 @@ struct readdir_callback {
int count;
};
-static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int fillonedir(void * __buf, const char * name, int namlen, off_t offset,
+ ino_t ino, unsigned int d_type)
{
struct readdir_callback * buf = (struct readdir_callback *) __buf;
struct old_linux_dirent * dirent;
@@ -184,7 +183,8 @@ struct getdents_callback {
int error;
};
-static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int filldir(void * __buf, const char * name, int namlen, off_t offset,
+ ino_t ino, unsigned int d_type)
{
struct linux_dirent * dirent;
struct getdents_callback * buf = (struct getdents_callback *) __buf;
@@ -240,3 +240,89 @@ out_putf:
out:
return error;
}
+
+/*
+ * And even better one including d_type field and 64bit d_ino and d_off.
+ */
+struct linux_dirent64 {
+ u64 d_ino;
+ s64 d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[0];
+};
+
+#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+struct getdents_callback64 {
+ struct linux_dirent64 * current_dir;
+ struct linux_dirent64 * previous;
+ int count;
+ int error;
+};
+
+static int filldir64(void * __buf, const char * name, int namlen, off_t offset,
+ ino_t ino, unsigned int d_type)
+{
+ struct linux_dirent64 * dirent, d;
+ struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
+ int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent) {
+ d.d_off = offset;
+ copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off));
+ }
+ dirent = buf->current_dir;
+ buf->previous = dirent;
+ memset(&d, 0, NAME_OFFSET(&d));
+ d.d_ino = ino;
+ d.d_reclen = reclen;
+ d.d_type = d_type;
+ copy_to_user(dirent, &d, NAME_OFFSET(&d));
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+ ((char *) dirent) += reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+}
+
+asmlinkage long sys_getdents64(unsigned int fd, void * dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent64 * lastdirent;
+ struct getdents_callback64 buf;
+ int error;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.current_dir = (struct linux_dirent64 *) dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdir(file, filldir64, &buf);
+ if (error < 0)
+ goto out_putf;
+ error = buf.error;
+ lastdirent = buf.previous;
+ if (lastdirent) {
+ struct linux_dirent64 d;
+ d.d_off = file->f_pos;
+ copy_to_user(&lastdirent->d_off, &d.d_off, sizeof(d.d_off));
+ error = count - buf.count;
+ }
+
+out_putf:
+ fput(file);
+out:
+ return error;
+}
+
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 8d01f17ba..081209a48 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -254,6 +254,10 @@ romfs_copyfrom(struct inode *i, void *dest, unsigned long offset, unsigned long
return res;
}
+static unsigned char romfs_dtype_table[] = {
+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO
+};
+
static int
romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
@@ -298,7 +302,8 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
nextfh = ntohl(ri.next);
if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
ino = ntohl(ri.spec);
- if (filldir(dirent, fsname, j, offset, ino) < 0) {
+ if (filldir(dirent, fsname, j, offset, ino,
+ romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) {
return stored;
}
stored++;
diff --git a/fs/smbfs/ChangeLog b/fs/smbfs/ChangeLog
index 893890334..a57b1cc67 100644
--- a/fs/smbfs/ChangeLog
+++ b/fs/smbfs/ChangeLog
@@ -1,5 +1,16 @@
ChangeLog for smbfs.
+2000-08-14 Urban Widmark <urban@svenskatest.se>
+
+ * dir.c: support case sensitive shares
+ * inode.c: ascii mount options
+ * proc.c: check length of paths to avoid buffer overflow
+ * proc.c: don't do interruptable_sleep in smb_retry to avoid signal
+ problem/race.
+ * proc.c: O_RDONLY & smb_revalidate_inode fix (tail -f)
+ * proc.c: add nls support
+ * sock.c: attempt to fix smb_data_callback (avoid infinite loop)
+
2000-07-25 Urban Widmark <urban@svenskatest.se>
* proc.c: fix 3 places where bad server responses could cause an Oops.
diff --git a/fs/smbfs/Makefile b/fs/smbfs/Makefile
index 3ea59f6cc..825b0156a 100644
--- a/fs/smbfs/Makefile
+++ b/fs/smbfs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := smbfs.o
-O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o
+O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o
M_OBJS := $(O_TARGET)
# If you want debugging output, you may add these flags to the EXTRA_CFLAGS
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 807d8f2e3..b2d5c4099 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -14,6 +14,7 @@
#include <linux/ctype.h>
#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
#include <linux/smbno.h>
#include "smb_debug.h"
@@ -66,12 +67,12 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
switch ((unsigned int) filp->f_pos)
{
case 0:
- if (filldir(dirent, ".", 1, 0, dir->i_ino) < 0)
+ if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
goto out;
filp->f_pos = 1;
case 1:
if (filldir(dirent, "..", 2, 1,
- dentry->d_parent->d_inode->i_ino) < 0)
+ dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
goto out;
filp->f_pos = 2;
}
@@ -127,7 +128,7 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
if (filldir(dirent, entry->name, entry->len,
- filp->f_pos, entry->ino) < 0)
+ filp->f_pos, entry->ino, DT_UNKNOWN) < 0)
break;
filp->f_pos += 1;
}
@@ -142,7 +143,7 @@ out:
}
/*
- * Note: in order to allow the smbclient process to open the
+ * Note: in order to allow the smbmount process to open the
* mount point, we don't revalidate if conn_pid is NULL.
*/
static int
@@ -190,6 +191,13 @@ static struct dentry_operations smbfs_dentry_operations =
d_delete: smb_delete_dentry,
};
+static struct dentry_operations smbfs_dentry_operations_case =
+{
+ d_revalidate: smb_lookup_validate,
+ d_delete: smb_delete_dentry,
+};
+
+
/*
* This is the callback when the dcache has a lookup hit.
*/
@@ -249,8 +257,7 @@ smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
if (a->len != b->len)
goto out;
- for (i=0; i < a->len; i++)
- {
+ for (i=0; i < a->len; i++) {
if (tolower(a->name[i]) != tolower(b->name[i]))
goto out;
}
@@ -300,6 +307,7 @@ smb_lookup(struct inode *dir, struct dentry *dentry)
struct smb_fattr finfo;
struct inode *inode;
int error;
+ struct smb_sb_info *server;
error = -ENAMETOOLONG;
if (dentry->d_name.len > SMB_MAXNAMELEN)
@@ -315,15 +323,18 @@ smb_lookup(struct inode *dir, struct dentry *dentry)
inode = NULL;
if (error == -ENOENT)
goto add_entry;
- if (!error)
- {
+ if (!error) {
error = -EACCES;
finfo.f_ino = smb_invent_inos(1);
inode = smb_iget(dir->i_sb, &finfo);
- if (inode)
- {
+ if (inode) {
add_entry:
- dentry->d_op = &smbfs_dentry_operations;
+ server = server_from_dentry(dentry);
+ if (server->mnt->flags & SMB_MOUNT_CASE)
+ dentry->d_op = &smbfs_dentry_operations_case;
+ else
+ dentry->d_op = &smbfs_dentry_operations;
+
d_add(dentry, inode);
smb_renew_times(dentry);
error = 0;
diff --git a/fs/smbfs/getopt.c b/fs/smbfs/getopt.c
new file mode 100644
index 000000000..0c5d111b3
--- /dev/null
+++ b/fs/smbfs/getopt.c
@@ -0,0 +1,61 @@
+/*
+ * getopt.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "getopt.h"
+
+/**
+ * smb_getopt - option parser
+ * @caller: name of the caller, for error messages
+ * @options: the options string
+ * @opts: an array of &struct option entries controlling parser operations
+ * @optopt: output; will contain the current option
+ * @optarg: output; will contain the value (if one exists)
+ * @flag: output; may be NULL; should point to a long for or'ing flags
+ * @value: output; may be NULL; will be overwritten with the integer value
+ * of the current argument.
+ *
+ * Helper to parse options on the format used by mount ("a=b,c=d,e,f").
+ * Returns opts->val if a matching entry in the 'opts' array is found,
+ * 0 when no more tokens are found, -1 if an error is encountered.
+ */
+int smb_getopt(char *caller, char **options, struct option *opts,
+ char **optopt, char **optarg, unsigned long *flag,
+ unsigned long *value)
+{
+ char *token;
+ char *val;
+ int i;
+
+ if ( (token = strsep(options, ",")) == NULL)
+ return 0;
+ *optopt = token;
+
+ *optarg = NULL;
+ if ((val = strchr (token, '=')) != NULL) {
+ *val++ = 0;
+ if (value)
+ *value = simple_strtoul(val, NULL, 0);
+ *optarg = val;
+ }
+
+ for (i = 0; opts[i].name != NULL; i++) {
+ if (!strcmp(opts[i].name, token)) {
+ if (opts[i].has_arg && (!val || !*val)) {
+ printk("%s: the %s option requires an argument\n",
+ caller, token);
+ return -1;
+ }
+
+ if (flag && opts[i].flag)
+ *flag |= opts[i].flag;
+
+ return opts[i].val;
+ }
+ }
+ printk("%s: Unrecognized mount option %s\n", caller, token);
+ return -1;
+}
diff --git a/fs/smbfs/getopt.h b/fs/smbfs/getopt.h
new file mode 100644
index 000000000..691f21103
--- /dev/null
+++ b/fs/smbfs/getopt.h
@@ -0,0 +1,15 @@
+#ifndef _LINUX_GETOPT_H
+#define _LINUX_GETOPT_H
+
+struct option {
+ const char *name;
+ int has_arg;
+ unsigned long flag;
+ int val;
+};
+
+extern int smb_getopt(char *caller, char **options, struct option *opts,
+ char **optopt, char **optarg, unsigned long *flag,
+ unsigned long *value);
+
+#endif /* _LINUX_GETOPT_H */
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index d7cb992b8..708951949 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -7,6 +7,7 @@
* Please add a note about your changes to smbfs in the ChangeLog file.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -20,6 +21,7 @@
#include <linux/file.h>
#include <linux/dcache.h>
#include <linux/smp_lock.h>
+#include <linux/nls.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
@@ -29,6 +31,7 @@
#include <asm/uaccess.h>
#include "smb_debug.h"
+#include "getopt.h"
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
@@ -282,6 +285,82 @@ smb_delete_inode(struct inode *ino)
clear_inode(ino);
}
+/* FIXME: flags and has_arg could probably be merged. */
+struct option opts[] = {
+ { "version", 1, 0, 'v' },
+ { "win95", 0, SMB_MOUNT_WIN95, 1 },
+ { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 },
+ { "dirattr", 0, SMB_MOUNT_DIRATTR, 1 },
+ { "case", 0, SMB_MOUNT_CASE, 1 },
+ { "uid", 1, 0, 'u' },
+ { "gid", 1, 0, 'g' },
+ { "file_mode", 1, 0, 'f' },
+ { "dir_mode", 1, 0, 'd' },
+ { "iocharset", 1, 0, 'i' },
+ { "codepage", 1, 0, 'c' },
+ { NULL, 0, 0, 0}
+};
+
+static int
+parse_options(struct smb_mount_data_kernel *mnt, char *options)
+{
+ int c;
+ unsigned long flags;
+ unsigned long value;
+ char *optarg;
+ char *optopt;
+
+ flags = 0;
+ while ( (c = smb_getopt("smbfs", &options, opts,
+ &optopt, &optarg, &flags, &value)) > 0) {
+
+ VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>");
+
+ switch (c) {
+ case 1:
+ /* got a "flag" option */
+ break;
+ case 'v':
+ if (value != SMB_MOUNT_VERSION) {
+ printk ("smbfs: Bad mount version %ld, expected %d\n",
+ value, SMB_MOUNT_VERSION);
+ return 0;
+ }
+ mnt->version = value;
+ break;
+ case 'u':
+ mnt->uid = value;
+ break;
+ case 'g':
+ mnt->gid = value;
+ break;
+ case 'f':
+ mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->file_mode |= S_IFREG;
+ break;
+ case 'd':
+ mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->dir_mode |= S_IFDIR;
+ break;
+ case 'i':
+ strncpy(mnt->codepage.local_name, optarg,
+ SMB_NLS_MAXNAMELEN);
+ break;
+ case 'c':
+ strncpy(mnt->codepage.remote_name, optarg,
+ SMB_NLS_MAXNAMELEN);
+ break;
+ default:
+ printk ("smbfs: Unrecognized mount option %s\n",
+ optopt);
+ return -1;
+ }
+ }
+ mnt->flags = flags;
+ return c;
+}
+
+
static void
smb_put_super(struct super_block *sb)
{
@@ -300,18 +379,32 @@ smb_put_super(struct super_block *sb)
kfree(sb->u.smbfs_sb.temp_buf);
if (server->packet)
smb_vfree(server->packet);
+
+ if(sb->u.smbfs_sb.remote_nls) {
+ unload_nls(sb->u.smbfs_sb.remote_nls);
+ sb->u.smbfs_sb.remote_nls = NULL;
+ }
+ if(sb->u.smbfs_sb.local_nls) {
+ unload_nls(sb->u.smbfs_sb.local_nls);
+ sb->u.smbfs_sb.local_nls = NULL;
+ }
}
struct super_block *
smb_read_super(struct super_block *sb, void *raw_data, int silent)
{
- struct smb_mount_data *mnt;
+ struct smb_mount_data_kernel *mnt;
+ struct smb_mount_data *oldmnt;
struct inode *root_inode;
struct smb_fattr root;
+ int ver;
if (!raw_data)
goto out_no_data;
- if (((struct smb_mount_data *) raw_data)->version != SMB_MOUNT_VERSION)
+
+ oldmnt = (struct smb_mount_data *) raw_data;
+ ver = oldmnt->version;
+ if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII)
goto out_wrong_data;
sb->s_blocksize = 1024; /* Eh... Is this correct? */
@@ -320,6 +413,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
sb->s_flags = 0;
sb->s_op = &smb_sops;
+ sb->u.smbfs_sb.mnt = NULL;
sb->u.smbfs_sb.sock_file = NULL;
init_MUTEX(&sb->u.smbfs_sb.sem);
init_waitqueue_head(&sb->u.smbfs_sb.wait);
@@ -332,30 +426,61 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
goto out_no_mem;
/* Allocate the global temp buffer */
- sb->u.smbfs_sb.temp_buf = kmalloc(SMB_MAXPATHLEN + 20, GFP_KERNEL);
+ sb->u.smbfs_sb.temp_buf = kmalloc(2*SMB_MAXPATHLEN + 20, GFP_KERNEL);
if (!sb->u.smbfs_sb.temp_buf)
goto out_no_temp;
+ /* Setup NLS stuff */
+ sb->u.smbfs_sb.remote_nls = NULL;
+ sb->u.smbfs_sb.local_nls = NULL;
+ sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20;
+
/* Allocate the mount data structure */
- mnt = kmalloc(sizeof(struct smb_mount_data), GFP_KERNEL);
+ /* FIXME: merge this with the other malloc and get a whole page? */
+ mnt = kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
if (!mnt)
goto out_no_mount;
- *mnt = *((struct smb_mount_data *) raw_data);
- /* FIXME: passes config flags in high bits of file mode. Should be a
- separate flags field. (but smbmount includes kernel headers ...) */
- mnt->version = (mnt->file_mode >> 9);
- mnt->file_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->file_mode |= S_IFREG;
- mnt->dir_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
- mnt->dir_mode |= S_IFDIR;
sb->u.smbfs_sb.mnt = mnt;
+
+ memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
+ strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
+ SMB_NLS_MAXNAMELEN);
+ strncpy(mnt->codepage.local_name, CONFIG_SMB_NLS_REMOTE,
+ SMB_NLS_MAXNAMELEN);
+
+ if (ver == SMB_MOUNT_OLDVERSION) {
+ mnt->version = oldmnt->version;
+
+ /* FIXME: is this enough to convert uid/gid's ? */
+ mnt->mounted_uid = oldmnt->mounted_uid;
+ mnt->uid = oldmnt->uid;
+ mnt->gid = oldmnt->gid;
+
+ mnt->file_mode =
+ oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->dir_mode =
+ oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->file_mode |= S_IFREG;
+ mnt->dir_mode |= S_IFDIR;
+
+ mnt->flags = (oldmnt->file_mode >> 9);
+ } else {
+ if (parse_options(mnt, raw_data))
+ goto out_bad_option;
+
+ mnt->mounted_uid = current->uid;
+ }
+ smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage);
+ if (!sb->u.smbfs_sb.convert)
+ PARANOIA("convert funcptr was NULL!\n");
+
/*
* Display the enabled options
* Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2)
*/
- if (mnt->version & SMB_FIX_OLDATTR)
+ if (mnt->flags & SMB_MOUNT_OLDATTR)
printk("SMBFS: Using core getattr (Win 95 speedup)\n");
- else if (mnt->version & SMB_FIX_DIRATTR)
+ else if (mnt->flags & SMB_MOUNT_DIRATTR)
printk("SMBFS: Using dir ff getattr\n");
/*
@@ -374,16 +499,18 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
out_no_root:
iput(root_inode);
+out_bad_option:
kfree(sb->u.smbfs_sb.mnt);
out_no_mount:
kfree(sb->u.smbfs_sb.temp_buf);
out_no_temp:
smb_vfree(sb->u.smbfs_sb.packet);
out_no_mem:
- printk(KERN_ERR "smb_read_super: allocation failure\n");
+ if (!sb->u.smbfs_sb.mnt)
+ printk(KERN_ERR "smb_read_super: allocation failure\n");
goto out_fail;
out_wrong_data:
- printk(KERN_ERR "SMBFS: need mount version %d\n", SMB_MOUNT_VERSION);
+ printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
goto out_fail;
out_no_data:
printk(KERN_ERR "smb_read_super: missing data argument\n");
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index e969320b7..7863cd2da 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -16,6 +16,7 @@
#include <linux/fcntl.h>
#include <linux/dcache.h>
#include <linux/dirent.h>
+#include <linux/nls.h>
#include <linux/smb_fs.h>
#include <linux/smbno.h>
@@ -25,10 +26,14 @@
#include "smb_debug.h"
+
/* Features. Undefine if they cause problems, this should perhaps be a
config option. */
#define SMBFS_POSIX_UNLINK 1
+/* Allow smb_retry to be interrupted. Not sure of the benefit ... */
+/* #define SMB_RETRY_INTR */
+
#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet) (*(packet+8))
#define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1))
@@ -48,6 +53,20 @@ static int
smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
struct smb_fattr *fattr);
+
+static inline void
+smb_lock_server(struct smb_sb_info *server)
+{
+ down(&(server->sem));
+}
+
+static inline void
+smb_unlock_server(struct smb_sb_info *server)
+{
+ up(&(server->sem));
+}
+
+
static void
str_upper(char *name, int len)
{
@@ -83,6 +102,96 @@ static void reverse_string(char *buf, int len)
}
}
+/* no conversion, just a wrapper for memcpy. */
+static int convert_memcpy(char *output, int olen,
+ const char *input, int ilen,
+ struct nls_table *nls_from,
+ struct nls_table *nls_to)
+{
+ memcpy(output, input, ilen);
+ return ilen;
+}
+
+/* convert from one "codepage" to another (possibly being utf8). */
+static int convert_cp(char *output, int olen,
+ const char *input, int ilen,
+ struct nls_table *nls_from,
+ struct nls_table *nls_to)
+{
+ int len = 0;
+ int n;
+ wchar_t ch;
+
+ if (!nls_from || !nls_to) {
+ PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to);
+ return convert_memcpy(output, olen, input, ilen, NULL, NULL);
+ }
+
+ while (ilen > 0) {
+ /* convert by changing to unicode and back to the new cp */
+ n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
+ if (n < 0)
+ goto out;
+ input += n;
+ ilen -= n;
+
+ n = nls_to->uni2char(ch, output, olen);
+ if (n < 0)
+ goto out;
+ output += n;
+ olen -= n;
+
+ len += n;
+ }
+out:
+ return len;
+}
+
+static int setcodepage(struct smb_sb_info *server,
+ struct nls_table **p, char *name)
+{
+ struct nls_table *nls;
+
+ if (!name || !*name) {
+ nls = NULL;
+ } else if ( (nls = load_nls(name)) == NULL) {
+ printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name);
+ return -EINVAL;
+ }
+
+ /* if already set, unload the previous one. */
+ if (*p)
+ unload_nls(*p);
+ *p = nls;
+
+ return 0;
+}
+
+/* Handles all changes to codepage settings. */
+int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
+{
+ int n;
+
+ smb_lock_server(server);
+
+ n = setcodepage(server, &server->local_nls, cp->local_name);
+ if (n != 0)
+ goto out;
+ n = setcodepage(server, &server->remote_nls, cp->remote_name);
+ if (n != 0)
+ setcodepage(server, &server->local_nls, NULL);
+
+out:
+ if (server->local_nls != NULL && server->remote_nls != NULL)
+ server->convert = convert_cp;
+ else
+ server->convert = convert_memcpy;
+
+ smb_unlock_server(server);
+ return n;
+}
+
+
/*****************************************************************************/
/* */
/* Encoding/Decoding section */
@@ -107,9 +216,11 @@ smb_encode_smb_length(__u8 * p, __u32 len)
* smb_build_path: build the path to entry and name storing it in buf.
* The path returned will have the trailing '\0'.
*/
-static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf)
+static int smb_build_path(struct smb_sb_info *server, char * buf,
+ struct dentry * entry, struct qstr * name)
{
char *path = buf;
+ int len;
if (entry == NULL)
goto test_name_and_out;
@@ -129,9 +240,16 @@ static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf)
* and store it in reversed order [see reverse_string()]
*/
for (;;) {
- memcpy(path, entry->d_name.name, entry->d_name.len);
- reverse_string(path, entry->d_name.len);
- path += entry->d_name.len;
+ if (entry->d_name.len > SMB_MAXNAMELEN)
+ return -ENAMETOOLONG;
+ if (path - buf + entry->d_name.len > SMB_MAXPATHLEN)
+ return -ENAMETOOLONG;
+
+ len = server->convert(path, SMB_MAXNAMELEN,
+ entry->d_name.name, entry->d_name.len,
+ server->local_nls, server->remote_nls);
+ reverse_string(path, len);
+ path += len;
*(path++) = '\\';
@@ -147,25 +265,28 @@ test_name_and_out:
if (name != NULL) {
*(path++) = '\\';
name_and_out:
- memcpy(path, name->name, name->len);
- path += name->len;
+ len = server->convert(path, SMB_MAXNAMELEN,
+ name->name, name->len,
+ server->local_nls, server->remote_nls);
+ path += len;
}
out:
*(path++) = '\0';
return (path-buf);
}
-static char *smb_encode_path(struct smb_sb_info *server, char *buf,
- struct dentry *dir, struct qstr *name)
+static int smb_encode_path(struct smb_sb_info *server, char *buf,
+ struct dentry *dir, struct qstr *name)
{
- char *start = buf;
-
- buf += smb_build_path(dir, name, buf);
+ int result;
+ result = smb_build_path(server, buf, dir, name);
+ if (result < 0)
+ goto out;
if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
- str_upper(start, buf - start);
-
- return buf;
+ str_upper(buf, result);
+out:
+ return result;
}
/* The following are taken directly from msdos-fs */
@@ -464,18 +585,6 @@ err_unknown:
return EIO;
}
-static inline void
-smb_lock_server(struct smb_sb_info *server)
-{
- down(&(server->sem));
-}
-
-static inline void
-smb_unlock_server(struct smb_sb_info *server)
-{
- up(&(server->sem));
-}
-
/*
* smb_retry: This function should be called when smb_request_ok has
* indicated an error. If the error was indicated because the
@@ -495,8 +604,7 @@ smb_retry(struct smb_sb_info *server)
smb_close_socket(server);
- if (pid == 0)
- {
+ if (pid == 0) {
printk(KERN_ERR "smb_retry: no connection process\n");
server->state = CONN_RETRIED;
goto out;
@@ -511,26 +619,35 @@ smb_retry(struct smb_sb_info *server)
* Note: use the "priv" flag, as a user process may need to reconnect.
*/
error = kill_proc(pid, SIGUSR1, 1);
- if (error)
- {
+ if (error) {
printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error);
goto out_restore;
}
- VERBOSE("signalled pid %d, waiting for new connection\n",
- server->conn_pid);
+ VERBOSE("signalled pid %d, waiting for new connection\n", pid);
/*
* Wait for the new connection.
*/
+#ifdef SMB_RETRY_INTR
interruptible_sleep_on_timeout(&server->wait, 5*HZ);
if (signal_pending(current))
printk(KERN_INFO "smb_retry: caught signal\n");
+#else
+ /*
+ * We don't want to be interrupted. For example, what if 'current'
+ * already has recieved a signal? sleep_on would terminate immediately
+ * and smbmount would not be able to re-establish connection.
+ *
+ * smbmount should be able to reconnect later, but it can't because
+ * it will get an -EIO on attempts to open the mountpoint!
+ */
+ sleep_on_timeout(&server->wait, 5*HZ);
+#endif
/*
* Check for a valid connection.
*/
- if (server->state == CONN_VALID)
- {
+ if (server->state == CONN_VALID) {
/* This should be changed to VERBOSE, except many smbfs
problems is with the userspace daemon not reconnecting. */
PARANOIA("sucessful, new pid=%d, generation=%d\n",
@@ -656,7 +773,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
(server->opt.max_xmit < 0x1000) &&
!(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
- server->mnt->version |= SMB_FIX_WIN95;
+ server->mnt->flags |= SMB_MOUNT_WIN95;
#ifdef SMBFS_DEBUG_VERBOSE
printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n");
#endif
@@ -667,7 +784,11 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
server->opt.capabilities);
out:
+#ifdef SMB_RETRY_INTR
wake_up_interruptible(&server->wait);
+#else
+ wake_up(&server->wait);
+#endif
return error;
out_putf:
@@ -738,7 +859,7 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
{
struct inode *ino = dentry->d_inode;
int mode, read_write = 0x42, read_only = 0x40;
- int error;
+ int res;
char *p;
/*
@@ -748,6 +869,9 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
mode = read_only;
#if 0
+ /* FIXME: why is this code not in? below we fix it so that a caller
+ wanting RO doesn't get RW. smb_revalidate_inode does some
+ optimization based on access mode. tail -f needs it to be correct. */
if (!(wish & (O_WRONLY | O_RDWR)))
mode = read_only;
#endif
@@ -757,20 +881,23 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
WSET(server->packet, smb_vwv0, mode);
WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
*p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ res = smb_encode_path(server, p, dentry, NULL);
+ if (res < 0)
+ goto out;
+ p += res;
+
smb_setup_bcc(server, p);
- error = smb_request_ok(server, SMBopen, 7, 0);
- if (error != 0)
- {
+ res = smb_request_ok(server, SMBopen, 7, 0);
+ if (res != 0) {
if (smb_retry(server))
goto retry;
if (mode == read_write &&
- (error == -EACCES || error == -ETXTBSY || error == -EROFS))
+ (res == -EACCES || res == -ETXTBSY || res == -EROFS))
{
VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n",
- DENTRY_PATH(dentry), error);
+ DENTRY_PATH(dentry), res);
mode = read_only;
goto retry;
}
@@ -783,10 +910,12 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
/* smb_vwv2 has mtime */
/* smb_vwv4 has size */
ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
+ if (!(wish & (O_WRONLY | O_RDWR)))
+ ino->u.smbfs_i.access = SMB_O_RDONLY;
ino->u.smbfs_i.open = server->generation;
out:
- return error;
+ return res;
}
/*
@@ -1025,7 +1154,7 @@ smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
{
struct smb_sb_info *server = server_from_dentry(dentry);
char *p;
- int error;
+ int result;
smb_lock_server(server);
@@ -1034,22 +1163,24 @@ smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
WSET(server->packet, smb_vwv0, attr);
DSET(server->packet, smb_vwv1, utc2local(server, ctime));
*p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
smb_setup_bcc(server, p);
- error = smb_request_ok(server, SMBcreate, 1, 0);
- if (error < 0)
- {
+ result = smb_request_ok(server, SMBcreate, 1, 0);
+ if (result < 0) {
if (smb_retry(server))
goto retry;
goto out;
}
*fileid = WVAL(server->packet, smb_vwv0);
- error = 0;
+ result = 0;
out:
smb_unlock_server(server);
- return error;
+ return result;
}
int
@@ -1064,14 +1195,22 @@ smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry)
retry:
p = smb_setup_header(server, SMBmv, 1, 0);
WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
+
*p++ = 4;
- p = smb_encode_path(server, p, old_dentry, NULL);
+ result = smb_encode_path(server, p, old_dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
+
*p++ = 4;
- p = smb_encode_path(server, p, new_dentry, NULL);
+ result = smb_encode_path(server, p, new_dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
+
smb_setup_bcc(server, p);
- if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
if (smb_retry(server))
goto retry;
goto out;
@@ -1097,12 +1236,14 @@ smb_proc_generic_command(struct dentry *dentry, __u8 command)
retry:
p = smb_setup_header(server, command, 0, 0);
*p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
smb_setup_bcc(server, p);
result = smb_request_ok(server, command, 0, 0);
- if (result < 0)
- {
+ if (result < 0) {
if (smb_retry(server))
goto retry;
goto out;
@@ -1165,11 +1306,13 @@ smb_proc_unlink(struct dentry *dentry)
p = smb_setup_header(server, SMBunlink, 1, 0);
WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
*p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
smb_setup_bcc(server, p);
- if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
#if SMBFS_POSIX_UNLINK
if (result == -EACCES && !flag) {
/* Posix semantics is for the read-only state
@@ -1220,8 +1363,7 @@ smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
*p++ = 0;
smb_setup_bcc(server, p);
- if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
if (smb_retry(server))
goto retry;
goto out;
@@ -1306,6 +1448,8 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
len--;
entry->len = len;
+ /* FIXME: These only work for ascii chars, and recent smbmount doesn't
+ allow the flag to be set anyway. Remove? */
switch (server->opt.case_handling) {
case SMB_CASE_UPPER:
str_upper(entry->name, len);
@@ -1316,7 +1460,13 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
default:
break;
}
- DEBUG1("len=%d, name=%.*s\n", len, len, entry->name);
+
+ entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+ entry->name, len,
+ server->remote_nls, server->local_nls);
+ entry->name = server->name_buf;
+
+ DEBUG1("len=%d, name=%.*s\n", entry->len, entry->len, entry->name);
return p + 22;
}
@@ -1355,7 +1505,10 @@ retry:
WSET(server->packet, smb_vwv1, aDIR);
*p++ = 4;
if (first == 1) {
- p = smb_encode_path(server, p, dir, &mask);
+ result = smb_encode_path(server, p, dir, &mask);
+ if (result < 0)
+ goto unlock_return;
+ p += result;
*p++ = 5;
WSET(p, 0, 0);
p += 2;
@@ -1467,12 +1620,11 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
switch (level) {
case 1:
len = *((unsigned char *) p + 22);
- entry->len = len;
entry->name = p + 23;
result = p + 24 + len;
VERBOSE("info 1 at %p, len=%d, name=%.*s\n",
- p, entry->len, entry->len, entry->name);
+ p, len, len, entry->name);
break;
case 260:
result = p + WVAL(p, 0);
@@ -1482,14 +1634,14 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
entry->name = p + 94;
if (len && entry->name[len-1] == '\0')
len--;
- entry->len = len;
VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
- p, entry->len, entry->len, entry->name);
+ p, len, len, entry->name);
break;
default:
PARANOIA("Unknown info level %d\n", level);
result = p + WVAL(p, 0);
+ goto out;
}
switch (server->opt.case_handling) {
@@ -1503,6 +1655,11 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
break;
}
+ entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+ entry->name, len,
+ server->remote_nls, server->local_nls);
+ entry->name = server->name_buf;
+out:
return result;
}
@@ -1561,7 +1718,12 @@ retry:
* Encode the initial path
*/
mask = param + 12;
- mask_len = smb_encode_path(server, mask, dir, &star) - mask;
+
+ mask_len = smb_encode_path(server, mask, dir, &star);
+ if (mask_len < 0) {
+ entries = mask_len;
+ goto unlock_return;
+ }
first = 1;
VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask);
@@ -1753,7 +1915,11 @@ smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
int mask_len, result;
retry:
- mask_len = smb_encode_path(server, mask, dentry, NULL) - mask;
+ mask_len = smb_encode_path(server, mask, dentry, NULL);
+ if (mask_len < 0) {
+ result = mask_len;
+ goto out;
+ }
VERBOSE("name=%s, len=%d\n", mask, mask_len);
WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
WSET(param, 2, 1); /* max count */
@@ -1828,7 +1994,10 @@ smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
retry:
p = smb_setup_header(server, SMBgetatr, 0, 0);
*p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
+ result = smb_encode_path(server, p, dir, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
smb_setup_bcc(server, p);
if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
@@ -1874,7 +2043,10 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, dir, NULL);
+ result = smb_encode_path(server, param + 6, dir, NULL);
+ if (result < 0)
+ goto out;
+ p = param + 6 + result;
result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
0, NULL, p - param, param,
@@ -1905,7 +2077,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
* Kludge alert: Win 95 swaps the date and time field,
* contrary to the CIFS docs and Win NT practice.
*/
- if (server->mnt->version & SMB_FIX_WIN95) {
+ if (server->mnt->flags & SMB_MOUNT_WIN95) {
off_date = 2;
off_time = 0;
}
@@ -1945,21 +2117,16 @@ smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
/*
* Select whether to use core or trans2 getattr.
+ * Win 95 appears to break with the trans2 getattr.
*/
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
- /*
- * Win 95 appears to break with the trans2 getattr.
- * Note: mnt->version options are set at mount time (inode.c)
- */
- if (server->mnt->version & (SMB_FIX_OLDATTR|SMB_FIX_WIN95))
- goto core_attr;
- if (server->mnt->version & SMB_FIX_DIRATTR)
+ if (server->opt.protocol < SMB_PROTOCOL_LANMAN2 ||
+ (server->mnt->flags & (SMB_MOUNT_OLDATTR|SMB_MOUNT_WIN95)) ) {
+ result = smb_proc_getattr_core(server, dir, fattr);
+ } else {
+ if (server->mnt->flags & SMB_MOUNT_DIRATTR)
result = smb_proc_getattr_ff(server, dir, fattr);
else
result = smb_proc_getattr_trans2(server, dir, fattr);
- } else {
- core_attr:
- result = smb_proc_getattr_core(server, dir, fattr);
}
smb_finish_dirent(server, fattr);
@@ -2008,14 +2175,16 @@ smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
WSET(server->packet, smb_vwv6, 0);
WSET(server->packet, smb_vwv7, 0);
*p++ = 4;
- p = smb_encode_path(server, p, dentry, NULL);
+ result = smb_encode_path(server, p, dentry, NULL);
+ if (result < 0)
+ goto out;
+ p += result;
*p++ = 4;
*p++ = 0;
smb_setup_bcc(server, p);
result = smb_request_ok(server, SMBsetatr, 0, 0);
- if (result < 0)
- {
+ if (result < 0) {
if (smb_retry(server))
goto retry;
goto out;
@@ -2073,8 +2242,7 @@ smb_proc_setattr_ext(struct smb_sb_info *server,
#endif
result = smb_request_ok(server, SMBsetattrE, 0, 0);
- if (result < 0)
- {
+ if (result < 0) {
if (smb_retry(server))
goto retry;
goto out;
@@ -2107,7 +2275,10 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, dir, NULL);
+ result = smb_encode_path(server, param + 6, dir, NULL);
+ if (result < 0)
+ goto out;
+ p = param + 6 + result;
WSET(data, 0, 0); /* creation time */
WSET(data, 2, 0);
@@ -2170,8 +2341,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
smb_lock_server(server);
/* setting the time on a Win95 server fails (tridge) */
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
- !(server->mnt->version & SMB_FIX_WIN95))
- {
+ !(server->mnt->flags & SMB_MOUNT_WIN95)) {
if (smb_is_open(inode) &&
inode->u.smbfs_i.access != SMB_O_RDONLY)
result = smb_proc_setattr_ext(server, inode, fattr);
@@ -2182,8 +2352,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
* Fail silently on directories ... timestamp can't be set?
*/
result = 0;
- if (S_ISREG(inode->i_mode))
- {
+ if (S_ISREG(inode->i_mode)) {
/*
* Set the mtime by opening and closing the file.
* Note that the file is opened read-only, but this
@@ -2192,8 +2361,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
result = -EACCES;
if (!smb_is_open(inode))
smb_proc_open(server, dentry, SMB_O_RDONLY);
- if (smb_is_open(inode))
- {
+ if (smb_is_open(inode)) {
inode->i_mtime = fattr->f_mtime;
result = smb_proc_close_inode(server, inode);
}
@@ -2208,7 +2376,7 @@ int
smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
{
struct smb_sb_info *server = &(sb->u.smbfs_sb);
- int error;
+ int result;
char *p;
smb_lock_server(server);
@@ -2216,8 +2384,7 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
retry:
smb_setup_header(server, SMBdskattr, 0, 0);
- if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
- {
+ if ((result = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
if (smb_retry(server))
goto retry;
goto out;
@@ -2226,11 +2393,11 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
attr->f_blocks = WVAL(p, 0);
attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
attr->f_bavail = attr->f_bfree = WVAL(p, 6);
- error = 0;
+ result = 0;
out:
smb_unlock_server(server);
- return error;
+ return result;
}
int
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 0c52bf871..01ae6ec87 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -111,12 +111,16 @@ smb_data_callback(void* ptr)
unsigned char peek_buf[4];
int result;
mm_segment_t fs;
+ int count = 100; /* this is a lot, we should have some data waiting */
+ int found = 0;
fs = get_fs();
set_fs(get_ds());
lock_kernel();
- while (1) {
+ while (count-- > 0) {
+ peek_buf[0] = 0;
+
result = -EIO;
if (job->sk->dead) {
PARANOIA("sock dead!\n");
@@ -125,7 +129,7 @@ smb_data_callback(void* ptr)
result = _recvfrom(socket, (void *) peek_buf, 1,
MSG_PEEK | MSG_DONTWAIT);
- if (result == -EAGAIN)
+ if (result < 0)
break;
if (peek_buf[0] != 0x85)
break;
@@ -136,13 +140,15 @@ smb_data_callback(void* ptr)
DEBUG1("got SESSION KEEPALIVE\n");
- if (result == -EAGAIN)
+ if (result < 0)
break;
+ found = 1;
}
unlock_kernel();
set_fs(fs);
- if (result != -EAGAIN)
+ DEBUG1("found=%d, count=%d, result=%d\n", found, count, result);
+ if (found)
found_data(job->sk);
kfree(ptr);
}
diff --git a/fs/stat.c b/fs/stat.c
index 18d1f7a88..e07b237e4 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -52,6 +52,10 @@ static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
SET_OLDSTAT_UID(tmp, inode->i_uid);
SET_OLDSTAT_GID(tmp, inode->i_gid);
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
+#if BITS_PER_LONG == 32
+ if (inode->i_size > 0x7fffffff)
+ return -EOVERFLOW;
+#endif
tmp.st_size = inode->i_size;
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
@@ -74,6 +78,10 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
SET_STAT_UID(tmp, inode->i_uid);
SET_STAT_GID(tmp, inode->i_gid);
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
+#if BITS_PER_LONG == 32
+ if (inode->i_size > 0x7fffffff)
+ return -EOVERFLOW;
+#endif
tmp.st_size = inode->i_size;
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
diff --git a/fs/super.c b/fs/super.c
index 8576d79d0..81a3fafc2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -10,13 +10,12 @@
* - umount system call
* - ustat system call
*
- * Added options to /proc/mounts
- * Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
- *
* GK 2/5/95 - Changed to support mounting the root fs via NFS
*
* Added kerneld support: Jacques Gelinas and Bjorn Ekwall
* Added change_root: Werner Almesberger & Hans Lermen, Feb '96
+ * Added options to /proc/mounts:
+ * Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
* Added devfs support: Richard Gooch <rgooch@atnf.csiro.au>, 13-JAN-1998
* Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
*/
@@ -428,6 +427,33 @@ static void remove_vfsmnt(struct vfsmount *mnt)
kfree(mnt);
}
+
+/* Use octal escapes, like mount does, for embedded spaces etc. */
+static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
+
+static int
+mangle(const unsigned char *s, char *buf, int len) {
+ char *sp;
+ int n;
+
+ sp = buf;
+ while(*s && sp-buf < len-3) {
+ for (n = 0; n < sizeof(need_escaping); n++) {
+ if (*s == need_escaping[n]) {
+ *sp++ = '\\';
+ *sp++ = '0' + ((*s & 0300) >> 6);
+ *sp++ = '0' + ((*s & 070) >> 3);
+ *sp++ = '0' + (*s & 07);
+ goto next;
+ }
+ }
+ *sp++ = *s;
+ next:
+ s++;
+ }
+ return sp - buf; /* no trailing NUL */
+}
+
static struct proc_fs_info {
int flag;
char *str;
@@ -466,27 +492,32 @@ int get_filesystem_info( char *buf )
struct proc_fs_info *fs_infop;
struct proc_nfs_info *nfs_infop;
struct nfs_server *nfss;
- int len = 0;
- char *path,*buffer = (char *) __get_free_page(GFP_KERNEL);
+ int len, prevlen;
+ char *path, *buffer = (char *) __get_free_page(GFP_KERNEL);
if (!buffer) return 0;
- for (p = vfsmntlist.next; p!=&vfsmntlist && len < PAGE_SIZE - 160;
- p = p->next) {
+ len = prevlen = 0;
+
+#define FREEROOM ((int)PAGE_SIZE-200-len)
+#define MANGLE(s) len += mangle((s), buf+len, FREEROOM);
+
+ for (p = vfsmntlist.next; p != &vfsmntlist; p = p->next) {
struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list);
if (!(tmp->mnt_flags & MNT_VISIBLE))
continue;
path = d_path(tmp->mnt_root, tmp, buffer, PAGE_SIZE);
if (!path)
continue;
- len += sprintf( buf + len, "%s %s %s %s",
- tmp->mnt_devname ? tmp->mnt_devname : "none", path,
- tmp->mnt_sb->s_type->name,
- tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw" );
+ MANGLE(tmp->mnt_devname ? tmp->mnt_devname : "none");
+ buf[len++] = ' ';
+ MANGLE(path);
+ buf[len++] = ' ';
+ MANGLE(tmp->mnt_sb->s_type->name);
+ len += sprintf(buf+len, " %s",
+ tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
- if (tmp->mnt_sb->s_flags & fs_infop->flag) {
- strcpy(buf + len, fs_infop->str);
- len += strlen(fs_infop->str);
- }
+ if (tmp->mnt_sb->s_flags & fs_infop->flag)
+ MANGLE(fs_infop->str);
}
if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
@@ -527,17 +558,24 @@ int get_filesystem_info( char *buf )
str = nfs_infop->str;
else
str = nfs_infop->nostr;
- strcpy(buf + len, str);
- len += strlen(str);
+ MANGLE(str);
}
- len += sprintf(buf+len, ",addr=%s",
- nfss->hostname);
+ len += sprintf(buf+len, ",addr=");
+ MANGLE(nfss->hostname);
+ }
+ len += sprintf(buf + len, " 0 0\n");
+ if (FREEROOM <= 3) {
+ len = prevlen;
+ len += sprintf(buf+len, "# truncated\n");
+ break;
}
- len += sprintf( buf + len, " 0 0\n" );
+ prevlen = len;
}
free_page((unsigned long) buffer);
return len;
+#undef MANGLE
+#undef FREEROOM
}
/**
@@ -775,7 +813,8 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
dev = to_kdev_t(bdev->bd_dev);
sb = get_super(dev);
if (sb) {
- if (fs_type == sb->s_type) {
+ if (fs_type == sb->s_type &&
+ ((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
path_release(&nd);
return sb;
}
@@ -1090,7 +1129,7 @@ asmlinkage long sys_umount(char * name, int flags)
if (retval)
goto out;
retval = -EINVAL;
- if (nd.dentry!=nd.mnt->mnt_root)
+ if (nd.dentry != nd.mnt->mnt_root)
goto dput_and_out;
retval = -EPERM;
@@ -1263,8 +1302,8 @@ static int copy_mount_options (const void *data, unsigned long *where)
* PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
* information (or be NULL).
*
- * NOTE! As old versions of mount() didn't use this setup, the flags
- * have to have a special 16-bit magic number in the high word:
+ * NOTE! As pre-0.97 versions of mount() didn't use this setup, the
+ * flags have to have a special 16-bit magic number in the high word:
* 0xC0ED. If this magic word isn't present, the flags and data info
* aren't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
@@ -1736,7 +1775,7 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
printk("okay\n");
return 0;
}
- printk(KERN_ERR "error %d\n",blivet);
+ printk(KERN_ERR "error %d\n", blivet);
return error;
}
/* FIXME: we should hold i_zombie on nd.dentry */
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 57968a839..5cdf5c605 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -61,7 +61,7 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
inode->i_ino, (off_t) filp->f_pos, sde.inode);
i = strnlen(sde.name, SYSV_NAMELEN);
- if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode) < 0) {
+ if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode, DT_UNKNOWN) < 0) {
brelse(bh);
return 0;
}
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 09121f0ef..9f093c536 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -94,7 +94,7 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
if ( filp->f_pos == 0 )
{
- if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino))
+ if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR))
return 0;
}
@@ -206,7 +206,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if (!lfi) /* parent directory */
{
- if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino))
+ if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR))
{
if (fibh.sbh != fibh.ebh)
udf_release_data(fibh.ebh);
@@ -219,7 +219,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
{
if ((flen = udf_get_filename(nameptr, fname, lfi)))
{
- if (filldir(dirent, fname, flen, filp->f_pos, iblock))
+ if (filldir(dirent, fname, flen, filp->f_pos, iblock, DT_UNKNOWN))
{
if (fibh.sbh != fibh.ebh)
udf_release_data(fibh.ebh);
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 08fa1f4bf..755198ded 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -122,11 +122,14 @@ revalidate:
* not the directory has been modified
* during the copy operation. */
unsigned long version = filp->f_version;
+ unsigned char d_type = DT_UNKNOWN;
UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
UFSD(("namlen %u\n", ufs_get_de_namlen(de)))
+ if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
+ d_type = de->d_u.d_44.d_type;
error = filldir(dirent, de->d_name, ufs_get_de_namlen(de),
- filp->f_pos, SWAB32(de->d_ino));
+ filp->f_pos, SWAB32(de->d_ino), d_type);
if (error)
break;
if (version != filp->f_version)
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index a84b8891f..b5c14c221 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -76,7 +76,7 @@ static int umsdos_dir_once ( void *buf,
if (d->count == 0) {
PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n",
len, name, offset));
- ret = d->filldir (d->dirbuf, name, len, offset, ino);
+ ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);
d->stop = ret < 0;
d->count = 1;
}
@@ -120,7 +120,7 @@ static int umsdos_readdir_x (struct inode *dir, struct file *filp,
Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
if (filldir (dirbuf, "DOS", 3,
- UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
+ UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) {
filp->f_pos++;
}
goto out_end;
@@ -235,7 +235,7 @@ dret->d_parent->d_name.name, dret->d_name.name);
*/
if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) {
if (filldir (dirbuf, entry.name, entry.name_len,
- cur_f_pos, inode->i_ino) < 0) {
+ cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {
pos = cur_f_pos;
}
Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index a477ade2c..ff208e6ac 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -33,7 +33,8 @@ static int rdir_filldir ( void *buf,
const char *name,
int name_len,
off_t offset,
- ino_t ino)
+ ino_t ino,
+ unsigned int d_type)
{
int ret = 0;
struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
@@ -48,11 +49,11 @@ static int rdir_filldir ( void *buf,
/* Make sure the .. entry points back to the pseudo_root */
ino = pseudo_root->i_ino;
}
- ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
+ ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN);
}
} else {
/* Any DOS directory */
- ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
+ ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN);
}
return ret;
}