Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs

Pull vfs pile 1 from Al Viro:
 "This is _not_ all; in particular, Miklos' and Jan's stuff is not there
  yet."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (64 commits)
  ext4: initialization of ext4_li_mtx needs to be done earlier
  debugfs-related mode_t whack-a-mole
  hfsplus: add an ioctl to bless files
  hfsplus: change finder_info to u32
  hfsplus: initialise userflags
  qnx4: new helper - try_extent()
  qnx4: get rid of qnx4_bread/qnx4_getblk
  take removal of PF_FORKNOEXEC to flush_old_exec()
  trim includes in inode.c
  um: uml_dup_mmap() relies on ->mmap_sem being held, but activate_mm() doesn't hold it
  um: embed ->stub_pages[] into mmu_context
  gadgetfs: list_for_each_safe() misuse
  ocfs2: fix leaks on failure exits in module_init
  ecryptfs: make register_filesystem() the last potential failure exit
  ntfs: forgets to unregister sysctls on register_filesystem() failure
  logfs: missing cleanup on register_filesystem() failure
  jfs: mising cleanup on register_filesystem() failure
  make configfs_pin_fs() return root dentry on success
  configfs: configfs_create_dir() has parent dentry in dentry->d_parent
  configfs: sanitize configfs_create()
  ...
  • Loading branch information
torvalds committed Mar 21, 2012
2 parents 3a990a5 + 07c0c5d commit e2a0883
Show file tree
Hide file tree
Showing 186 changed files with 5,360 additions and 4,141 deletions.
2 changes: 1 addition & 1 deletion Documentation/filesystems/debugfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ file.
void __iomem *base;
};

struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
struct dentry *parent,
struct debugfs_regset32 *regset);

Expand Down
6 changes: 6 additions & 0 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -429,3 +429,9 @@ filemap_write_and_wait_range() so that all dirty pages are synced out properly.
You must also keep in mind that ->fsync() is not called with i_mutex held
anymore, so if you require i_mutex locking you must make sure to take it and
release it yourself.

--
[mandatory]
d_alloc_root() is gone, along with a lot of bugs caused by code
misusing it. Replacement: d_make_root(inode). The difference is,
d_make_root() drops the reference to inode if dentry allocation fails.
174 changes: 174 additions & 0 deletions Documentation/filesystems/qnx6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
The QNX6 Filesystem
===================

The qnx6fs is used by newer QNX operating system versions. (e.g. Neutrino)
It got introduced in QNX 6.4.0 and is used default since 6.4.1.

Option
======

mmi_fs Mount filesystem as used for example by Audi MMI 3G system

Specification
=============

qnx6fs shares many properties with traditional Unix filesystems. It has the
concepts of blocks, inodes and directories.
On QNX it is possible to create little endian and big endian qnx6 filesystems.
This feature makes it possible to create and use a different endianness fs
for the target (QNX is used on quite a range of embedded systems) plattform
running on a different endianess.
The Linux driver handles endianness transparently. (LE and BE)

Blocks
------

The space in the device or file is split up into blocks. These are a fixed
size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
created.
Blockpointers are 32bit, so the maximum space that can be adressed is
2^32 * 4096 bytes or 16TB

The superblocks
---------------

The superblock contains all global information about the filesystem.
Each qnx6fs got two superblocks, each one having a 64bit serial number.
That serial number is used to identify the "active" superblock.
In write mode with reach new snapshot (after each synchronous write), the
serial of the new master superblock is increased (old superblock serial + 1)

So basically the snapshot functionality is realized by an atomic final
update of the serial number. Before updating that serial, all modifications
are done by copying all modified blocks during that specific write request
(or period) and building up a new (stable) filesystem structure under the
inactive superblock.

Each superblock holds a set of root inodes for the different filesystem
parts. (Inode, Bitmap and Longfilenames)
Each of these root nodes holds information like total size of the stored
data and the adressing levels in that specific tree.
If the level value is 0, up to 16 direct blocks can be adressed by each
node.
Level 1 adds an additional indirect adressing level where each indirect
adressing block holds up to blocksize / 4 bytes pointers to data blocks.
Level 2 adds an additional indirect adressig block level (so, already up
to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a

Unused block pointers are always set to ~0 - regardless of root node,
indirect adressing blocks or inodes.
Data leaves are always on the lowest level. So no data is stored on upper
tree levels.

The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
The Audi MMI 3G first superblock directly starts at byte 0.
Second superblock position can either be calculated from the superblock
information (total number of filesystem blocks) or by taking the highest
device address, zeroing the last 3 bytes and then substracting 0x1000 from
that address.

0x1000 is the size reserved for each superblock - regardless of the
blocksize of the filesystem.

Inodes
------

Each object in the filesystem is represented by an inode. (index node)
The inode structure contains pointers to the filesystem blocks which contain
the data held in the object and all of the metadata about an object except
its longname. (filenames longer than 27 characters)
The metadata about an object includes the permissions, owner, group, flags,
size, number of blocks used, access time, change time and modification time.

Object mode field is POSIX format. (which makes things easier)

There are also pointers to the first 16 blocks, if the object data can be
adressed with 16 direct blocks.
For more than 16 blocks an indirect adressing in form of another tree is
used. (scheme is the same as the one used for the superblock root nodes)

The filesize is stored 64bit. Inode counting starts with 1. (whilst long
filename inodes start with 0)

Directories
-----------

A directory is a filesystem object and has an inode just like a file.
It is a specially formatted file containing records which associate each
name with an inode number.
'.' inode number points to the directory inode
'..' inode number points to the parent directory inode
Eeach filename record additionally got a filename length field.

One special case are long filenames or subdirectory names.
These got set a filename length field of 0xff in the corresponding directory
record plus the longfile inode number also stored in that record.
With that longfilename inode number, the longfilename tree can be walked
starting with the superblock longfilename root node pointers.

Special files
-------------

Symbolic links are also filesystem objects with inodes. They got a specific
bit in the inode mode field identifying them as symbolic link.
The directory entry file inode pointer points to the target file inode.

Hard links got an inode, a directory entry, but a specific mode bit set,
no block pointers and the directory file record pointing to the target file
inode.

Character and block special devices do not exist in QNX as those files
are handled by the QNX kernel/drivers and created in /dev independant of the
underlaying filesystem.

Long filenames
--------------

Long filenames are stored in a seperate adressing tree. The staring point
is the longfilename root node in the active superblock.
Each data block (tree leaves) holds one long filename. That filename is
limited to 510 bytes. The first two starting bytes are used as length field
for the actual filename.
If that structure shall fit for all allowed blocksizes, it is clear why there
is a limit of 510 bytes for the actual filename stored.

Bitmap
------

The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap
root node in the superblock and each bit in the bitmap represents one
filesystem block.
The first block is block 0, which starts 0x1000 after superblock start.
So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical
address at which block 0 is located.

Bits at the end of the last bitmap block are set to 1, if the device is
smaller than addressing space in the bitmap.

Bitmap system area
------------------

The bitmap itself is devided into three parts.
First the system area, that is split into two halfs.
Then userspace.

The requirement for a static, fixed preallocated system area comes from how
qnx6fs deals with writes.
Each superblock got it's own half of the system area. So superblock #1
always uses blocks from the lower half whilst superblock #2 just writes to
blocks represented by the upper half bitmap system area bits.

Bitmap blocks, Inode blocks and indirect addressing blocks for those two
tree structures are treated as system blocks.

The rational behind that is that a write request can work on a new snapshot
(system area of the inactive - resp. lower serial numbered superblock) while
at the same time there is still a complete stable filesystem structer in the
other half of the system area.

When finished with writing (a sync write is completed, the maximum sync leap
time or a filesystem sync is requested), serial of the previously inactive
superblock atomically is increased and the fs switches over to that - then
stable declared - superblock.

For all data outside the system area, blocks are just copied while writing.
1 change: 1 addition & 0 deletions Documentation/ioctl/ioctl-number.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Code Seq#(hex) Include File Comments
'h' 00-7F conflict! Charon filesystem
<mailto:[email protected]>
'h' 00-1F linux/hpet.h conflict!
'h' 80-8F fs/hfsplus/ioctl.c
'i' 00-3F linux/i2o-dev.h conflict!
'i' 0B-1F linux/ipmi.h conflict!
'i' 80-8F linux/i8k.h
Expand Down
3 changes: 2 additions & 1 deletion arch/alpha/kernel/binfmt_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static struct linux_binfmt loader_format = {

static int __init init_loader_binfmt(void)
{
return insert_binfmt(&loader_format);
insert_binfmt(&loader_format);
return 0;
}
arch_initcall(init_loader_binfmt);
14 changes: 7 additions & 7 deletions arch/powerpc/platforms/cell/spufs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,9 +757,9 @@ spufs_create_root(struct super_block *sb, void *data)
goto out_iput;

ret = -ENOMEM;
sb->s_root = d_alloc_root(inode);
sb->s_root = d_make_root(inode);
if (!sb->s_root)
goto out_iput;
goto out;

return 0;
out_iput:
Expand Down Expand Up @@ -828,19 +828,19 @@ static int __init spufs_init(void)
ret = spu_sched_init();
if (ret)
goto out_cache;
ret = register_filesystem(&spufs_type);
ret = register_spu_syscalls(&spufs_calls);
if (ret)
goto out_sched;
ret = register_spu_syscalls(&spufs_calls);
ret = register_filesystem(&spufs_type);
if (ret)
goto out_fs;
goto out_syscalls;

spufs_init_isolated_loader();

return 0;

out_fs:
unregister_filesystem(&spufs_type);
out_syscalls:
unregister_spu_syscalls(&spufs_calls);
out_sched:
spu_sched_exit();
out_cache:
Expand Down
6 changes: 2 additions & 4 deletions arch/s390/hypfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,9 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM;
root_inode->i_op = &simple_dir_inode_operations;
root_inode->i_fop = &simple_dir_operations;
sb->s_root = root_dentry = d_alloc_root(root_inode);
if (!root_dentry) {
iput(root_inode);
sb->s_root = root_dentry = d_make_root(root_inode);
if (!root_dentry)
return -ENOMEM;
}
if (MACHINE_IS_VM)
rc = hypfs_vm_create_files(sb, root_dentry);
else
Expand Down
2 changes: 1 addition & 1 deletion arch/um/include/asm/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
typedef struct mm_context {
struct mm_id id;
struct uml_arch_mm_context arch;
struct page **stub_pages;
struct page *stub_pages[2];
} mm_context_t;

extern void __switch_mm(struct mm_id * mm_idp);
Expand Down
11 changes: 9 additions & 2 deletions arch/um/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <linux/sched.h>
#include <asm/mmu.h>

extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
extern void uml_setup_stubs(struct mm_struct *mm);
extern void arch_exit_mmap(struct mm_struct *mm);

#define deactivate_mm(tsk,mm) do { } while (0)
Expand All @@ -23,7 +23,9 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
* when the new ->mm is used for the first time.
*/
__switch_mm(&new->context.id);
arch_dup_mmap(old, new);
down_write(&new->mmap_sem);
uml_setup_stubs(new);
up_write(&new->mmap_sem);
}

static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
Expand All @@ -39,6 +41,11 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
}
}

static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
{
uml_setup_stubs(mm);
}

static inline void enter_lazy_tlb(struct mm_struct *mm,
struct task_struct *tsk)
{
Expand Down
25 changes: 6 additions & 19 deletions arch/um/kernel/skas/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
goto out_free;
}

to_mm->stub_pages = NULL;

return 0;

out_free:
Expand All @@ -103,7 +101,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
return ret;
}

void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
void uml_setup_stubs(struct mm_struct *mm)
{
struct page **pages;
int err, ret;
Expand All @@ -120,29 +118,20 @@ void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
if (ret)
goto out;

pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL);
if (pages == NULL) {
printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page "
"pointers\n");
goto out;
}

pages[0] = virt_to_page(&__syscall_stub_start);
pages[1] = virt_to_page(mm->context.id.stack);
mm->context.stub_pages = pages;
mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start);
mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);

/* dup_mmap already holds mmap_sem */
err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
VM_READ | VM_MAYREAD | VM_EXEC |
VM_MAYEXEC | VM_DONTCOPY, pages);
VM_MAYEXEC | VM_DONTCOPY,
mm->context.stub_pages);
if (err) {
printk(KERN_ERR "install_special_mapping returned %d\n", err);
goto out_free;
goto out;
}
return;

out_free:
kfree(pages);
out:
force_sigsegv(SIGSEGV, current);
}
Expand All @@ -151,8 +140,6 @@ void arch_exit_mmap(struct mm_struct *mm)
{
pte_t *pte;

if (mm->context.stub_pages != NULL)
kfree(mm->context.stub_pages);
pte = virt_to_pte(mm, STUB_CODE);
if (pte != NULL)
pte_clear(mm, STUB_CODE, pte);
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/ia32/ia32_aout.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,6 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
}

install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;

if (N_MAGIC(ex) == OMAGIC) {
unsigned long text_addr, map_size;
Expand Down Expand Up @@ -519,7 +518,8 @@ static int load_aout_library(struct file *file)

static int __init init_aout_binfmt(void)
{
return register_binfmt(&aout_format);
register_binfmt(&aout_format);
return 0;
}

static void __exit exit_aout_binfmt(void)
Expand Down
Loading

0 comments on commit e2a0883

Please sign in to comment.