diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-21 15:38:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-21 15:38:14 -0700 |
commit | fd9be4ce2e1eb407a8152f823698cc0d652bbec8 (patch) | |
tree | b1cc279fa5b1f90995253f007564f001aa20c743 /include | |
parent | b1af9ccce9cff5b48c37424dbdbb3aa9021915db (diff) | |
parent | ad775f5a8faa5845377f093ca11caf577404add9 (diff) |
Merge branch 'ro-bind.b6' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'ro-bind.b6' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (24 commits)
[PATCH] r/o bind mounts: debugging for missed calls
[PATCH] r/o bind mounts: honor mount writer counts at remount
[PATCH] r/o bind mounts: track numbers of writers to mounts
[PATCH] r/o bind mounts: check mnt instead of superblock directly
[PATCH] r/o bind mounts: elevate count for xfs timestamp updates
[PATCH] r/o bind mounts: make access() use new r/o helper
[PATCH] r/o bind mounts: write counts for truncate()
[PATCH] r/o bind mounts: elevate write count for chmod/chown callers
[PATCH] r/o bind mounts: elevate write count for open()s
[PATCH] r/o bind mounts: elevate write count for ioctls()
[PATCH] r/o bind mounts: write count for file_update_time()
[PATCH] r/o bind mounts: elevate write count for do_utimes()
[PATCH] r/o bind mounts: write counts for touch_atime()
[PATCH] r/o bind mounts: elevate write count for ncp_ioctl()
[PATCH] r/o bind mounts: elevate write count for xattr_permission() callers
[PATCH] r/o bind mounts: get write access for vfs_rename() callers
[PATCH] r/o bind mounts: write counts for link/symlink
[PATCH] r/o bind mounts: get callers of vfs_mknod/create/mkdir()
[PATCH] r/o bind mounts: elevate write count for rmdir and unlink.
[PATCH] r/o bind mounts: drop write during emergency remount
...
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/file.h | 1 | ||||
-rw-r--r-- | include/linux/fs.h | 52 | ||||
-rw-r--r-- | include/linux/mount.h | 11 |
3 files changed, 63 insertions, 1 deletions
diff --git a/include/linux/file.h b/include/linux/file.h index 7239baac81a..653477021e4 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -61,6 +61,7 @@ extern struct kmem_cache *filp_cachep; extern void __fput(struct file *); extern void fput(struct file *); +extern void drop_file_write_access(struct file *file); struct file_operations; struct vfsmount; diff --git a/include/linux/fs.h b/include/linux/fs.h index b84b848431f..d1eeea669d2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -776,6 +776,9 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index) index < ra->start + ra->size); } +#define FILE_MNT_WRITE_TAKEN 1 +#define FILE_MNT_WRITE_RELEASED 2 + struct file { /* * fu_list becomes invalid after file_free is called and queued via @@ -810,6 +813,9 @@ struct file { spinlock_t f_ep_lock; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; +#ifdef CONFIG_DEBUG_WRITECOUNT + unsigned long f_mnt_write_state; +#endif }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); @@ -818,6 +824,49 @@ extern spinlock_t files_lock; #define get_file(x) atomic_inc(&(x)->f_count) #define file_count(x) atomic_read(&(x)->f_count) +#ifdef CONFIG_DEBUG_WRITECOUNT +static inline void file_take_write(struct file *f) +{ + WARN_ON(f->f_mnt_write_state != 0); + f->f_mnt_write_state = FILE_MNT_WRITE_TAKEN; +} +static inline void file_release_write(struct file *f) +{ + f->f_mnt_write_state |= FILE_MNT_WRITE_RELEASED; +} +static inline void file_reset_write(struct file *f) +{ + f->f_mnt_write_state = 0; +} +static inline void file_check_state(struct file *f) +{ + /* + * At this point, either both or neither of these bits + * should be set. + */ + WARN_ON(f->f_mnt_write_state == FILE_MNT_WRITE_TAKEN); + WARN_ON(f->f_mnt_write_state == FILE_MNT_WRITE_RELEASED); +} +static inline int file_check_writeable(struct file *f) +{ + if (f->f_mnt_write_state == FILE_MNT_WRITE_TAKEN) + return 0; + printk(KERN_WARNING "writeable file with no " + "mnt_want_write()\n"); + WARN_ON(1); + return -EINVAL; +} +#else /* !CONFIG_DEBUG_WRITECOUNT */ +static inline void file_take_write(struct file *filp) {} +static inline void file_release_write(struct file *filp) {} +static inline void file_reset_write(struct file *filp) {} +static inline void file_check_state(struct file *filp) {} +static inline int file_check_writeable(struct file *filp) +{ + return 0; +} +#endif /* CONFIG_DEBUG_WRITECOUNT */ + #define MAX_NON_LFS ((1UL<<31) - 1) /* Page cache limit. The filesystems should put that into their s_maxbytes @@ -1735,7 +1784,8 @@ extern struct file *create_read_pipe(struct file *f); extern struct file *create_write_pipe(void); extern void free_write_pipe(struct file *); -extern int open_namei(int dfd, const char *, int, int, struct nameidata *); +extern struct file *do_filp_open(int dfd, const char *pathname, + int open_flag, int mode); extern int may_open(struct nameidata *, int, int); extern int kernel_read(struct file *, unsigned long, char *, unsigned long); diff --git a/include/linux/mount.h b/include/linux/mount.h index 5ee2df217cd..d6600e3f7e4 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/list.h> +#include <linux/nodemask.h> #include <linux/spinlock.h> #include <asm/atomic.h> @@ -28,8 +29,10 @@ struct mnt_namespace; #define MNT_NOATIME 0x08 #define MNT_NODIRATIME 0x10 #define MNT_RELATIME 0x20 +#define MNT_READONLY 0x40 /* does the user want this to be r/o? */ #define MNT_SHRINKABLE 0x100 +#define MNT_IMBALANCED_WRITE_COUNT 0x200 /* just for debugging */ #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ @@ -62,6 +65,11 @@ struct vfsmount { int mnt_expiry_mark; /* true if marked for expiry */ int mnt_pinned; int mnt_ghosts; + /* + * This value is not stable unless all of the mnt_writers[] spinlocks + * are held, and all mnt_writer[]s on this mount have 0 as their ->count + */ + atomic_t __mnt_writers; }; static inline struct vfsmount *mntget(struct vfsmount *mnt) @@ -71,9 +79,12 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt) return mnt; } +extern int mnt_want_write(struct vfsmount *mnt); +extern void mnt_drop_write(struct vfsmount *mnt); extern void mntput_no_expire(struct vfsmount *mnt); extern void mnt_pin(struct vfsmount *mnt); extern void mnt_unpin(struct vfsmount *mnt); +extern int __mnt_is_readonly(struct vfsmount *mnt); static inline void mntput(struct vfsmount *mnt) { |