* [PATCH 1/9] fat: kill is_bad_inode() check
@ 2008-04-20 18:13 OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 2/9] fat: fat_notify_change() and check_mode() cleanup OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
FAT doesn't need to check bad inode anymore.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/inode.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff -puN fs/fat/inode.c~fat-cleanup-bad-inode fs/fat/inode.c
--- linux-2.6/fs/fat/inode.c~fat-cleanup-bad-inode 2008-02-15 17:44:56.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/inode.c 2008-02-15 17:44:56.000000000 +0900
@@ -433,11 +433,8 @@ EXPORT_SYMBOL_GPL(fat_build_inode);
static void fat_delete_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
-
- if (!is_bad_inode(inode)) {
- inode->i_size = 0;
- fat_truncate(inode);
- }
+ inode->i_size = 0;
+ fat_truncate(inode);
clear_inode(inode);
}
@@ -445,8 +442,6 @@ static void fat_clear_inode(struct inode
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
- if (is_bad_inode(inode))
- return;
lock_kernel();
spin_lock(&sbi->inode_hash_lock);
fat_cache_inval_inode(inode);
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/9] fat: fat_notify_change() and check_mode() cleanup
2008-04-20 18:13 [PATCH 1/9] fat: kill is_bad_inode() check OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 3/9] fat: fat_setattr() fix OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
- Rename fat_notify_change() to fat_setattr()
- check_mode() cleanup
- Change layout of code
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/file.c | 183 +++++++++++++++++++++-------------------------
fs/msdos/namei.c | 2
fs/vfat/namei.c | 2
include/linux/msdos_fs.h | 2
4 files changed, 87 insertions(+), 102 deletions(-)
diff -puN fs/fat/file.c~fat_notify_change-cleanup fs/fat/file.c
--- linux-2.6/fs/fat/file.c~fat_notify_change-cleanup 2008-02-15 19:09:45.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/file.c 2008-02-15 19:31:52.000000000 +0900
@@ -155,104 +155,6 @@ out:
return err;
}
-static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
-{
- mode_t req = mode & ~S_IFMT;
-
- /*
- * Of the r and x bits, all (subject to umask) must be present. Of the
- * w bits, either all (subject to umask) or none must be present.
- */
-
- if (S_ISREG(mode)) {
- req &= ~sbi->options.fs_fmask;
-
- if ((req & (S_IRUGO | S_IXUGO)) !=
- ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
- return -EPERM;
-
- if ((req & S_IWUGO) != 0 &&
- (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
- return -EPERM;
- } else if (S_ISDIR(mode)) {
- req &= ~sbi->options.fs_dmask;
-
- if ((req & (S_IRUGO | S_IXUGO)) !=
- ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
- return -EPERM;
-
- if ((req & S_IWUGO) != 0 &&
- (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
- return -EPERM;
- } else {
- return -EPERM;
- }
-
- return 0;
-}
-
-int fat_notify_change(struct dentry *dentry, struct iattr *attr)
-{
- struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
- struct inode *inode = dentry->d_inode;
- int mask, error = 0;
-
- lock_kernel();
-
- /*
- * Expand the file. Since inode_setattr() updates ->i_size
- * before calling the ->truncate(), but FAT needs to fill the
- * hole before it.
- */
- if (attr->ia_valid & ATTR_SIZE) {
- if (attr->ia_size > inode->i_size) {
- error = fat_cont_expand(inode, attr->ia_size);
- if (error || attr->ia_valid == ATTR_SIZE)
- goto out;
- attr->ia_valid &= ~ATTR_SIZE;
- }
- }
-
- error = inode_change_ok(inode, attr);
- if (error) {
- if (sbi->options.quiet)
- error = 0;
- goto out;
- }
- if (((attr->ia_valid & ATTR_UID) &&
- (attr->ia_uid != sbi->options.fs_uid)) ||
- ((attr->ia_valid & ATTR_GID) &&
- (attr->ia_gid != sbi->options.fs_gid)))
- error = -EPERM;
-
- if (error) {
- if (sbi->options.quiet)
- error = 0;
- goto out;
- }
-
- if (attr->ia_valid & ATTR_MODE) {
- error = check_mode(sbi, attr->ia_mode);
- if (error != 0 && !sbi->options.quiet)
- goto out;
- }
-
- error = inode_setattr(inode, attr);
- if (error)
- goto out;
-
- if (S_ISDIR(inode->i_mode))
- mask = sbi->options.fs_dmask;
- else
- mask = sbi->options.fs_fmask;
- inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
-out:
- unlock_kernel();
- return error;
-}
-
-EXPORT_SYMBOL_GPL(fat_notify_change);
-
/* Free all clusters after the skip'th cluster. */
static int fat_free(struct inode *inode, int skip)
{
@@ -353,8 +255,91 @@ int fat_getattr(struct vfsmount *mnt, st
}
EXPORT_SYMBOL_GPL(fat_getattr);
+static int fat_check_mode(const struct msdos_sb_info *sbi, mode_t mode)
+{
+ mode_t mask, req = mode & ~S_IFMT;
+
+ if (S_ISREG(mode))
+ mask = sbi->options.fs_fmask;
+ else
+ mask = sbi->options.fs_dmask;
+
+ /*
+ * Of the r and x bits, all (subject to umask) must be present. Of the
+ * w bits, either all (subject to umask) or none must be present.
+ */
+ req &= ~mask;
+ if ((req & (S_IRUGO | S_IXUGO)) != ((S_IRUGO | S_IXUGO) & ~mask))
+ return -EPERM;
+ if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask)))
+ return -EPERM;
+
+ return 0;
+}
+
+int fat_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
+ struct inode *inode = dentry->d_inode;
+ int mask, error = 0;
+
+ lock_kernel();
+
+ /*
+ * Expand the file. Since inode_setattr() updates ->i_size
+ * before calling the ->truncate(), but FAT needs to fill the
+ * hole before it.
+ */
+ if (attr->ia_valid & ATTR_SIZE) {
+ if (attr->ia_size > inode->i_size) {
+ error = fat_cont_expand(inode, attr->ia_size);
+ if (error || attr->ia_valid == ATTR_SIZE)
+ goto out;
+ attr->ia_valid &= ~ATTR_SIZE;
+ }
+ }
+
+ error = inode_change_ok(inode, attr);
+ if (error) {
+ if (sbi->options.quiet)
+ error = 0;
+ goto out;
+ }
+ if (((attr->ia_valid & ATTR_UID) &&
+ (attr->ia_uid != sbi->options.fs_uid)) ||
+ ((attr->ia_valid & ATTR_GID) &&
+ (attr->ia_gid != sbi->options.fs_gid)))
+ error = -EPERM;
+
+ if (error) {
+ if (sbi->options.quiet)
+ error = 0;
+ goto out;
+ }
+
+ if (attr->ia_valid & ATTR_MODE) {
+ error = fat_check_mode(sbi, attr->ia_mode);
+ if (error != 0 && !sbi->options.quiet)
+ goto out;
+ }
+
+ error = inode_setattr(inode, attr);
+ if (error)
+ goto out;
+
+ if (S_ISDIR(inode->i_mode))
+ mask = sbi->options.fs_dmask;
+ else
+ mask = sbi->options.fs_fmask;
+ inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
+out:
+ unlock_kernel();
+ return error;
+}
+EXPORT_SYMBOL_GPL(fat_setattr);
+
const struct inode_operations fat_file_inode_operations = {
.truncate = fat_truncate,
- .setattr = fat_notify_change,
+ .setattr = fat_setattr,
.getattr = fat_getattr,
};
diff -puN fs/msdos/namei.c~fat_notify_change-cleanup fs/msdos/namei.c
--- linux-2.6/fs/msdos/namei.c~fat_notify_change-cleanup 2008-02-15 19:13:05.000000000 +0900
+++ linux-2.6-hirofumi/fs/msdos/namei.c 2008-02-15 19:13:09.000000000 +0900
@@ -653,7 +653,7 @@ static const struct inode_operations msd
.mkdir = msdos_mkdir,
.rmdir = msdos_rmdir,
.rename = msdos_rename,
- .setattr = fat_notify_change,
+ .setattr = fat_setattr,
.getattr = fat_getattr,
};
diff -puN fs/vfat/namei.c~fat_notify_change-cleanup fs/vfat/namei.c
--- linux-2.6/fs/vfat/namei.c~fat_notify_change-cleanup 2008-02-15 19:13:18.000000000 +0900
+++ linux-2.6-hirofumi/fs/vfat/namei.c 2008-02-15 19:13:23.000000000 +0900
@@ -1003,7 +1003,7 @@ static const struct inode_operations vfa
.mkdir = vfat_mkdir,
.rmdir = vfat_rmdir,
.rename = vfat_rename,
- .setattr = fat_notify_change,
+ .setattr = fat_setattr,
.getattr = fat_getattr,
};
diff -puN include/linux/msdos_fs.h~fat_notify_change-cleanup include/linux/msdos_fs.h
--- linux-2.6/include/linux/msdos_fs.h~fat_notify_change-cleanup 2008-02-15 19:13:32.000000000 +0900
+++ linux-2.6-hirofumi/include/linux/msdos_fs.h 2008-02-15 19:13:37.000000000 +0900
@@ -401,7 +401,7 @@ extern int fat_generic_ioctl(struct inod
unsigned int cmd, unsigned long arg);
extern const struct file_operations fat_file_operations;
extern const struct inode_operations fat_file_inode_operations;
-extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
+extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
extern void fat_truncate(struct inode *inode);
extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/9] fat: fat_setattr() fix
2008-04-20 18:13 ` [PATCH 2/9] fat: fat_notify_change() and check_mode() cleanup OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 4/9] fat: Add allow_utime option OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
Fix fat_setattr() on the case of showexec option. If user specified
showexec option, inode->i_mode may not have S_IXUGO. This just use
inode->i_mode to fix it.
And with this patch, we don't allow chmod() on memory inode, it's just
bad behaviour. IOW, we allow changing S_IWUGO only which can be stored
to disk.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/file.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff -puN fs/fat/file.c~fat_setattr-fix fs/fat/file.c
--- linux-2.6/fs/fat/file.c~fat_setattr-fix 2008-02-20 15:28:06.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/file.c 2008-02-21 11:42:25.000000000 +0900
@@ -255,7 +255,8 @@ int fat_getattr(struct vfsmount *mnt, st
}
EXPORT_SYMBOL_GPL(fat_getattr);
-static int fat_check_mode(const struct msdos_sb_info *sbi, mode_t mode)
+static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode,
+ mode_t mode)
{
mode_t mask, req = mode & ~S_IFMT;
@@ -269,7 +270,7 @@ static int fat_check_mode(const struct m
* w bits, either all (subject to umask) or none must be present.
*/
req &= ~mask;
- if ((req & (S_IRUGO | S_IXUGO)) != ((S_IRUGO | S_IXUGO) & ~mask))
+ if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
return -EPERM;
if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask)))
return -EPERM;
@@ -308,7 +309,9 @@ int fat_setattr(struct dentry *dentry, s
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != sbi->options.fs_uid)) ||
((attr->ia_valid & ATTR_GID) &&
- (attr->ia_gid != sbi->options.fs_gid)))
+ (attr->ia_gid != sbi->options.fs_gid)) ||
+ ((attr->ia_valid & ATTR_MODE) &&
+ fat_check_mode(sbi, inode, attr->ia_mode) < 0))
error = -EPERM;
if (error) {
@@ -317,12 +320,6 @@ int fat_setattr(struct dentry *dentry, s
goto out;
}
- if (attr->ia_valid & ATTR_MODE) {
- error = fat_check_mode(sbi, attr->ia_mode);
- if (error != 0 && !sbi->options.quiet)
- goto out;
- }
-
error = inode_setattr(inode, attr);
if (error)
goto out;
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/9] fat: Add allow_utime option
2008-04-20 18:13 ` [PATCH 3/9] fat: fat_setattr() fix OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 5/9] fat: Update free_clusters even if it is untrusted OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
Normally utime(2) checks current process is owner of the file, or it
has CAP_FOWNER capability. But FAT filesystem doesn't have uid/gid as
on disk info, so normal check is too unflexible.
With this option you can relax it.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
Documentation/filesystems/vfat.txt | 15 +++++++++++++++
fs/fat/file.c | 24 ++++++++++++++++++++++++
fs/fat/inode.c | 18 +++++++++++++++---
include/linux/msdos_fs.h | 1 +
4 files changed, 55 insertions(+), 3 deletions(-)
diff -puN fs/fat/file.c~fat_allow_utime fs/fat/file.c
--- linux-2.6/fs/fat/file.c~fat_allow_utime 2008-03-14 05:02:22.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/file.c 2008-03-14 05:36:19.000000000 +0900
@@ -278,11 +278,27 @@ static int fat_check_mode(const struct m
return 0;
}
+static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
+{
+ mode_t allow_utime = sbi->options.allow_utime;
+
+ if (current->fsuid != inode->i_uid) {
+ if (in_group_p(inode->i_gid))
+ allow_utime >>= 3;
+ if (allow_utime & MAY_WRITE)
+ return 1;
+ }
+
+ /* use a default check */
+ return 0;
+}
+
int fat_setattr(struct dentry *dentry, struct iattr *attr)
{
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
struct inode *inode = dentry->d_inode;
int mask, error = 0;
+ unsigned int ia_valid;
lock_kernel();
@@ -300,7 +316,15 @@ int fat_setattr(struct dentry *dentry, s
}
}
+ /* Check for setting the inode time. */
+ ia_valid = attr->ia_valid;
+ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
+ if (fat_allow_set_time(sbi, inode))
+ attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET);
+ }
+
error = inode_change_ok(inode, attr);
+ attr->ia_valid = ia_valid;
if (error) {
if (sbi->options.quiet)
error = 0;
diff -puN fs/fat/inode.c~fat_allow_utime fs/fat/inode.c
--- linux-2.6/fs/fat/inode.c~fat_allow_utime 2008-03-14 05:02:22.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/inode.c 2008-03-14 05:35:37.000000000 +0900
@@ -785,6 +785,8 @@ static int fat_show_options(struct seq_f
seq_printf(m, ",gid=%u", opts->fs_gid);
seq_printf(m, ",fmask=%04o", opts->fs_fmask);
seq_printf(m, ",dmask=%04o", opts->fs_dmask);
+ if (opts->allow_utime)
+ seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
if (sbi->nls_disk)
seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
if (isvfat) {
@@ -840,9 +842,9 @@ static int fat_show_options(struct seq_f
enum {
Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
- Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase,
- Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
- Opt_dots, Opt_nodots,
+ Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage,
+ Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug,
+ Opt_immutable, Opt_dots, Opt_nodots,
Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
@@ -861,6 +863,7 @@ static match_table_t fat_tokens = {
{Opt_umask, "umask=%o"},
{Opt_dmask, "dmask=%o"},
{Opt_fmask, "fmask=%o"},
+ {Opt_allow_utime, "allow_utime=%o"},
{Opt_codepage, "codepage=%u"},
{Opt_usefree, "usefree"},
{Opt_nocase, "nocase"},
@@ -932,6 +935,7 @@ static int parse_options(char *options,
opts->fs_uid = current->uid;
opts->fs_gid = current->gid;
opts->fs_fmask = opts->fs_dmask = current->fs->umask;
+ opts->allow_utime = -1;
opts->codepage = fat_default_codepage;
opts->iocharset = fat_default_iocharset;
if (is_vfat)
@@ -1019,6 +1023,11 @@ static int parse_options(char *options,
return 0;
opts->fs_fmask = option;
break;
+ case Opt_allow_utime:
+ if (match_octal(&args[0], &option))
+ return 0;
+ opts->allow_utime = option & (S_IWGRP | S_IWOTH);
+ break;
case Opt_codepage:
if (match_int(&args[0], &option))
return 0;
@@ -1101,6 +1110,9 @@ static int parse_options(char *options,
" for FAT filesystems, filesystem will be case sensitive!\n");
}
+ /* If user doesn't specify allow_utime, it's initialized from dmask. */
+ if (opts->allow_utime == (unsigned short)-1)
+ opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
if (opts->unicode_xlate)
opts->utf8 = 0;
diff -puN include/linux/msdos_fs.h~fat_allow_utime include/linux/msdos_fs.h
--- linux-2.6/include/linux/msdos_fs.h~fat_allow_utime 2008-03-14 05:02:22.000000000 +0900
+++ linux-2.6-hirofumi/include/linux/msdos_fs.h 2008-03-14 05:35:37.000000000 +0900
@@ -195,6 +195,7 @@ struct fat_mount_options {
char *iocharset; /* Charset used for filename input/display */
unsigned short shortname; /* flags for shortname display/create rule */
unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+ unsigned short allow_utime;/* permission for setting the [am]time */
unsigned quiet:1, /* set = fake successful chmods and chowns */
showexec:1, /* set = only set x bit for com/exe/bat */
sys_immutable:1, /* set = system files are immutable */
diff -puN Documentation/filesystems/vfat.txt~fat_allow_utime Documentation/filesystems/vfat.txt
--- linux-2.6/Documentation/filesystems/vfat.txt~fat_allow_utime 2008-03-14 05:02:22.000000000 +0900
+++ linux-2.6-hirofumi/Documentation/filesystems/vfat.txt 2008-03-14 05:02:22.000000000 +0900
@@ -17,6 +17,21 @@ dmask=### -- The permission mask for
fmask=### -- The permission mask for files.
The default is the umask of current process.
+allow_utime=### -- This option controls the permission check of mtime/atime.
+
+ 20 - If current process is in group of file's group ID,
+ you can change timestamp.
+ 2 - Other users can change timestamp.
+
+ The default is set from `dmask' option. (If the directory is
+ writable, utime(2) is also allowed. I.e. ~dmask & 022)
+
+ Normally utime(2) checks current process is owner of
+ the file, or it has CAP_FOWNER capability. But FAT
+ filesystem doesn't have uid/gid on disk, so normal
+ check is too unflexible. With this option you can
+ relax it.
+
codepage=### -- Sets the codepage number for converting to shortname
characters on FAT filesystem.
By default, FAT_DEFAULT_CODEPAGE setting is used.
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6/9] fat: Remove fat_clusters_flush()
2008-04-20 18:13 ` [PATCH 5/9] fat: Update free_clusters even if it is untrusted OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 7/9] Add balance_dirty_pages_ratelimited() to cont_expand_zero() OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
This removes unneeded fat_clusters_flush().
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/fatent.c | 2 --
1 file changed, 2 deletions(-)
diff -puN fs/fat/fatent.c~fat-remove-fat_clusters_flush fs/fat/fatent.c
--- linux-2.6/fs/fat/fatent.c~fat-remove-fat_clusters_flush 2008-04-19 11:55:07.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/fatent.c 2008-04-19 11:55:07.000000000 +0900
@@ -585,8 +585,6 @@ error:
brelse(bhs[i]);
unlock_fat(sbi);
- fat_clusters_flush(sb);
-
return err;
}
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/9] fat: Update free_clusters even if it is untrusted
2008-04-20 18:13 ` [PATCH 4/9] fat: Add allow_utime option OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 6/9] fat: Remove fat_clusters_flush() OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
Currently, free_clusters is not updated until it is trusted, because
Windows doesn't update it correctly.
But if user is using FAT driver of Linux, it updates free_clusters
correctly. Instead, this updates it even if it's untrusted, so if
free_clustes is correct, now keep correct value.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/fatent.c | 7 +++++--
fs/fat/inode.c | 7 ++++---
include/linux/msdos_fs.h | 1 +
3 files changed, 10 insertions(+), 5 deletions(-)
diff -puN include/linux/msdos_fs.h~fat_fix-free_clusters-check include/linux/msdos_fs.h
--- linux-2.6/include/linux/msdos_fs.h~fat_fix-free_clusters-check 2008-03-14 05:38:40.000000000 +0900
+++ linux-2.6-hirofumi/include/linux/msdos_fs.h 2008-03-14 05:38:40.000000000 +0900
@@ -233,6 +233,7 @@ struct msdos_sb_info {
struct mutex fat_lock;
unsigned int prev_free; /* previously allocated cluster number */
unsigned int free_clusters; /* -1 if undefined */
+ unsigned int free_clus_valid; /* is free_clusters valid? */
struct fat_mount_options options;
struct nls_table *nls_disk; /* Codepage used on disk */
struct nls_table *nls_io; /* Charset used for input and display */
diff -puN fs/fat/inode.c~fat_fix-free_clusters-check fs/fat/inode.c
--- linux-2.6/fs/fat/inode.c~fat_fix-free_clusters-check 2008-03-14 05:38:40.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/inode.c 2008-03-14 05:38:40.000000000 +0900
@@ -537,7 +537,7 @@ static int fat_statfs(struct dentry *den
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
/* If the count of free cluster is still unknown, counts it here. */
- if (sbi->free_clusters == -1) {
+ if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
int err = fat_count_free_clusters(dentry->d_sb);
if (err)
return err;
@@ -1274,6 +1274,7 @@ int fat_fill_super(struct super_block *s
sbi->fat_length = le16_to_cpu(b->fat_length);
sbi->root_cluster = 0;
sbi->free_clusters = -1; /* Don't know yet */
+ sbi->free_clus_valid = 0;
sbi->prev_free = FAT_START_ENT;
if (!sbi->fat_length && b->fat32_length) {
@@ -1309,8 +1310,8 @@ int fat_fill_super(struct super_block *s
sbi->fsinfo_sector);
} else {
if (sbi->options.usefree)
- sbi->free_clusters =
- le32_to_cpu(fsinfo->free_clusters);
+ sbi->free_clus_valid = 1;
+ sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
}
diff -puN fs/fat/fatent.c~fat_fix-free_clusters-check fs/fat/fatent.c
--- linux-2.6/fs/fat/fatent.c~fat_fix-free_clusters-check 2008-03-14 05:38:40.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/fatent.c 2008-03-14 05:38:40.000000000 +0900
@@ -450,7 +450,8 @@ int fat_alloc_clusters(struct inode *ino
BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */
lock_fat(sbi);
- if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) {
+ if (sbi->free_clusters != -1 && sbi->free_clus_valid &&
+ sbi->free_clusters < nr_cluster) {
unlock_fat(sbi);
return -ENOSPC;
}
@@ -504,6 +505,7 @@ int fat_alloc_clusters(struct inode *ino
/* Couldn't allocate the free entries */
sbi->free_clusters = 0;
+ sbi->free_clus_valid = 1;
sb->s_dirt = 1;
err = -ENOSPC;
@@ -615,7 +617,7 @@ int fat_count_free_clusters(struct super
int err = 0, free;
lock_fat(sbi);
- if (sbi->free_clusters != -1)
+ if (sbi->free_clusters != -1 && sbi->free_clus_valid)
goto out;
reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits;
@@ -643,6 +645,7 @@ int fat_count_free_clusters(struct super
} while (fat_ent_next(sbi, &fatent));
}
sbi->free_clusters = free;
+ sbi->free_clus_valid = 1;
sb->s_dirt = 1;
fatent_brelse(&fatent);
out:
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 7/9] Add balance_dirty_pages_ratelimited() to cont_expand_zero()
2008-04-20 18:13 ` [PATCH 6/9] fat: Remove fat_clusters_flush() OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 8/9] vfat: bug fix for vfat cannot handle filename with 255 OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
On the systems, ftruncate() which expand size for FAT became the cause
of OOM. The cont_expand_zero() filled all memory with dirty pages,
and since disk is very slow, limit of page scanning was exceeded, then
it triggered OOM.
This adds balance_dirty_pages_ratelimited() to avoid filling memory
with dirty pages.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/buffer.c | 2 ++
1 file changed, 2 insertions(+)
diff -puN fs/buffer.c~cont_expand_zero-fix fs/buffer.c
--- linux-2.6/fs/buffer.c~cont_expand_zero-fix 2008-04-05 18:22:57.000000000 +0900
+++ linux-2.6-hirofumi/fs/buffer.c 2008-04-05 18:22:57.000000000 +0900
@@ -2251,6 +2251,8 @@ int cont_expand_zero(struct file *file,
goto out;
BUG_ON(err != len);
err = 0;
+
+ balance_dirty_pages_ratelimited(mapping);
}
/* page covers the boundary, find the boundary offset */
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 8/9] vfat: bug fix for vfat cannot handle filename with 255
2008-04-20 18:13 ` [PATCH 7/9] Add balance_dirty_pages_ratelimited() to cont_expand_zero() OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 9/9] fat: use __getname() OGAWA Hirofumi
0 siblings, 1 reply; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi, ek9852
From: Keith Mok <ek9852@gmail.com>
This patch fix the problem that the buffer allocated for convert of
unicode to utf8 in fat/dir.c is too small.
And cannot handle filename with 255 asian characters when mounted with
utf8 options.
Also it fix the filename length limitation checking in vfat/namei.c that
the filename length should be checked against the number of converted
unicode characters.
Not the length before NLS/UTF8 converted.
Signed-off-by: Keith Mok <ek9852@gmail.com>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/dir.c | 44 ++++++++++++++++++++++++++++----------------
fs/vfat/namei.c | 25 +++++++++++--------------
2 files changed, 39 insertions(+), 30 deletions(-)
diff -puN fs/fat/dir.c~fat_vfat-fix-filename-handing fs/fat/dir.c
--- linux-2.6/fs/fat/dir.c~fat_vfat-fix-filename-handing 2008-04-19 11:55:08.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/dir.c 2008-04-21 00:59:00.000000000 +0900
@@ -124,8 +124,8 @@ static inline int fat_get_entry(struct i
* but ignore that right now.
* Ahem... Stack smashing in ring 0 isn't fun. Fixed.
*/
-static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
- struct nls_table *nls)
+static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len,
+ int uni_xlate, struct nls_table *nls)
{
wchar_t *ip, ec;
unsigned char *op, nc;
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *as
ip = uni;
op = ascii;
- while (*ip) {
+ while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) {
ec = *ip++;
if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
op += charlen;
+ len -= charlen;
} else {
if (uni_xlate == 1) {
*op = ':';
@@ -149,16 +150,19 @@ static int uni16_to_x8(unsigned char *as
ec >>= 4;
}
op += 5;
+ len -= 5;
} else {
*op++ = '?';
+ len--;
}
}
- /* We have some slack there, so it's OK */
- if (op>ascii+256) {
- op = ascii + 256;
- break;
- }
}
+
+ if (unlikely(*ip)) {
+ printk(KERN_WARNING "FAT: filename was truncated while "
+ "converting.");
+ }
+
*op = 0;
return (op - ascii);
}
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode,
struct nls_table *nls_io = sbi->nls_io;
struct nls_table *nls_disk = sbi->nls_disk;
wchar_t bufuname[14];
- unsigned char xlate_len, nr_slots;
+ unsigned char nr_slots;
+ int xlate_len;
wchar_t *unicode = NULL;
- unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */
+ unsigned char work[MSDOS_NAME];
+ unsigned char *bufname = NULL;
int uni_xlate = sbi->options.unicode_xlate;
int utf8 = sbi->options.utf8;
int anycase = (sbi->options.name_check != 's');
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode,
loff_t cpos = 0;
int chl, i, j, last_u, err;
+ bufname = (unsigned char*)__get_free_page(GFP_KERNEL);
+ if (!bufname)
+ return -ENOMEM;
+
err = -ENOENT;
while(1) {
if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
@@ -386,8 +396,8 @@ parse_record:
bufuname[last_u] = 0x0000;
xlate_len = utf8
- ?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
- :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, bufuname, PAGE_SIZE)
+ :uni16_to_x8(bufname, bufuname, PAGE_SIZE, uni_xlate, nls_io);
if (xlate_len == name_len)
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
(anycase && !nls_strnicmp(nls_io, name, bufname,
@@ -396,8 +406,8 @@ parse_record:
if (nr_slots) {
xlate_len = utf8
- ?utf8_wcstombs(bufname, unicode, sizeof(bufname))
- :uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, unicode, PAGE_SIZE)
+ :uni16_to_x8(bufname, unicode, PAGE_SIZE, uni_xlate, nls_io);
if (xlate_len != name_len)
continue;
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -416,6 +426,8 @@ Found:
sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
err = 0;
EODir:
+ if (bufname)
+ free_page((unsigned long)bufname);
if (unicode)
free_page((unsigned long)unicode);
@@ -598,7 +610,7 @@ parse_record:
if (isvfat) {
bufuname[j] = 0x0000;
i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
- : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+ : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io);
}
fill_name = bufname;
@@ -610,7 +622,7 @@ parse_record:
int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0]));
int long_len = utf8
? utf8_wcstombs(longname, unicode, buf_size)
- : uni16_to_x8(longname, unicode, uni_xlate, nls_io);
+ : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io);
if (!both) {
fill_name = longname;
diff -puN fs/vfat/namei.c~fat_vfat-fix-filename-handing fs/vfat/namei.c
--- linux-2.6/fs/vfat/namei.c~fat_vfat-fix-filename-handing 2008-04-19 11:55:08.000000000 +0900
+++ linux-2.6-hirofumi/fs/vfat/namei.c 2008-04-21 00:57:11.000000000 +0900
@@ -176,15 +176,10 @@ static inline int vfat_is_used_badchars(
for (i = 0; i < len; i++)
if (vfat_bad_char(s[i]))
return -EINVAL;
- return 0;
-}
-static int vfat_valid_longname(const unsigned char *name, unsigned int len)
-{
- if (name[len - 1] == ' ')
+ if (s[i - 1] == ' ') /* last character cannot be space */
return -EINVAL;
- if (len >= 256)
- return -ENAMETOOLONG;
+
return 0;
}
@@ -485,11 +480,14 @@ xlate_to_uni(const unsigned char *name,
*/
*outlen -= (name_len - len);
+ if (*outlen > 255)
+ return -ENAMETOOLONG;
+
op = &outname[*outlen * sizeof(wchar_t)];
} else {
if (nls) {
for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260;
+ i < len && *outlen <= 255;
*outlen += 1)
{
if (escape && (*ip == ':')) {
@@ -525,18 +523,20 @@ xlate_to_uni(const unsigned char *name,
op += 2;
}
}
+ if (i < len)
+ return -ENAMETOOLONG;
} else {
for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260;
+ i < len && *outlen <= 255;
i++, *outlen += 1)
{
*op++ = *ip++;
*op++ = 0;
}
+ if (i < len)
+ return -ENAMETOOLONG;
}
}
- if (*outlen > 260)
- return -ENAMETOOLONG;
*longlen = *outlen;
if (*outlen % 13) {
@@ -574,9 +574,6 @@ static int vfat_build_slots(struct inode
loff_t offset;
*nr_slots = 0;
- err = vfat_valid_longname(name, len);
- if (err)
- return err;
page = __get_free_page(GFP_KERNEL);
if (!page)
_
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 9/9] fat: use __getname()
2008-04-20 18:13 ` [PATCH 8/9] vfat: bug fix for vfat cannot handle filename with 255 OGAWA Hirofumi
@ 2008-04-20 18:13 ` OGAWA Hirofumi
0 siblings, 0 replies; 9+ messages in thread
From: OGAWA Hirofumi @ 2008-04-20 18:13 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, hirofumi
__getname() is faster than __get_free_page(). Use it.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---
fs/fat/dir.c | 20 ++++++++++----------
fs/vfat/namei.c | 10 ++++------
2 files changed, 14 insertions(+), 16 deletions(-)
diff -puN fs/vfat/namei.c~fat_use-__getname fs/vfat/namei.c
--- linux-2.6/fs/vfat/namei.c~fat_use-__getname 2008-04-21 01:36:07.000000000 +0900
+++ linux-2.6-hirofumi/fs/vfat/namei.c 2008-04-21 01:36:07.000000000 +0900
@@ -472,7 +472,7 @@ xlate_to_uni(const unsigned char *name,
if (utf8) {
int name_len = strlen(name);
- *outlen = utf8_mbstowcs((wchar_t *)outname, name, PAGE_SIZE);
+ *outlen = utf8_mbstowcs((wchar_t *)outname, name, PATH_MAX);
/*
* We stripped '.'s before and set len appropriately,
@@ -565,7 +565,6 @@ static int vfat_build_slots(struct inode
struct fat_mount_options *opts = &sbi->options;
struct msdos_dir_slot *ps;
struct msdos_dir_entry *de;
- unsigned long page;
unsigned char cksum, lcase;
unsigned char msdos_name[MSDOS_NAME];
wchar_t *uname;
@@ -575,11 +574,10 @@ static int vfat_build_slots(struct inode
*nr_slots = 0;
- page = __get_free_page(GFP_KERNEL);
- if (!page)
+ uname = __getname();
+ if (!uname)
return -ENOMEM;
- uname = (wchar_t *)page;
err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
opts->unicode_xlate, opts->utf8, sbi->nls_io);
if (err)
@@ -631,7 +629,7 @@ shortname:
de->starthi = cpu_to_le16(cluster >> 16);
de->size = 0;
out_free:
- free_page(page);
+ __putname(uname);
return err;
}
diff -puN fs/fat/dir.c~fat_use-__getname fs/fat/dir.c
--- linux-2.6/fs/fat/dir.c~fat_use-__getname 2008-04-21 01:36:07.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/dir.c 2008-04-21 01:36:07.000000000 +0900
@@ -247,7 +247,7 @@ static int fat_parse_long(struct inode *
unsigned char id, slot, slots, alias_checksum;
if (!*unicode) {
- *unicode = (wchar_t *)__get_free_page(GFP_KERNEL);
+ *unicode = __getname();
if (!*unicode) {
brelse(*bh);
return -ENOMEM;
@@ -327,7 +327,7 @@ int fat_search_long(struct inode *inode,
loff_t cpos = 0;
int chl, i, j, last_u, err;
- bufname = (unsigned char*)__get_free_page(GFP_KERNEL);
+ bufname = __getname();
if (!bufname)
return -ENOMEM;
@@ -396,8 +396,8 @@ parse_record:
bufuname[last_u] = 0x0000;
xlate_len = utf8
- ?utf8_wcstombs(bufname, bufuname, PAGE_SIZE)
- :uni16_to_x8(bufname, bufuname, PAGE_SIZE, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, bufuname, PATH_MAX)
+ :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io);
if (xlate_len == name_len)
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
(anycase && !nls_strnicmp(nls_io, name, bufname,
@@ -406,8 +406,8 @@ parse_record:
if (nr_slots) {
xlate_len = utf8
- ?utf8_wcstombs(bufname, unicode, PAGE_SIZE)
- :uni16_to_x8(bufname, unicode, PAGE_SIZE, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, unicode, PATH_MAX)
+ :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io);
if (xlate_len != name_len)
continue;
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -427,9 +427,9 @@ Found:
err = 0;
EODir:
if (bufname)
- free_page((unsigned long)bufname);
+ __putname(bufname);
if (unicode)
- free_page((unsigned long)unicode);
+ __putname(unicode);
return err;
}
@@ -619,7 +619,7 @@ parse_record:
/* convert the unicode long name. 261 is maximum size
* of unicode buffer. (13 * slots + nul) */
void *longname = unicode + 261;
- int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0]));
+ int buf_size = PATH_MAX - (261 * sizeof(unicode[0]));
int long_len = utf8
? utf8_wcstombs(longname, unicode, buf_size)
: uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io);
@@ -652,7 +652,7 @@ EODir:
FillFailed:
brelse(bh);
if (unicode)
- free_page((unsigned long)unicode);
+ __putname(unicode);
out:
unlock_kernel();
return ret;
_
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-04-20 18:29 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-04-20 18:13 [PATCH 1/9] fat: kill is_bad_inode() check OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 2/9] fat: fat_notify_change() and check_mode() cleanup OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 3/9] fat: fat_setattr() fix OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 4/9] fat: Add allow_utime option OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 5/9] fat: Update free_clusters even if it is untrusted OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 6/9] fat: Remove fat_clusters_flush() OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 7/9] Add balance_dirty_pages_ratelimited() to cont_expand_zero() OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 8/9] vfat: bug fix for vfat cannot handle filename with 255 OGAWA Hirofumi
2008-04-20 18:13 ` [PATCH 9/9] fat: use __getname() OGAWA Hirofumi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®