]>
Commit | Line | Data |
---|---|---|
8ac6a477 JR |
1 | diff -urNp linux-1253/fs/buffer.c linux-1255/fs/buffer.c |
2 | --- linux-1253/fs/buffer.c | |
3 | +++ linux-1255/fs/buffer.c | |
4 | @@ -366,6 +366,34 @@ void sync_dev(kdev_t dev) | |
5 | fsync_dev(dev); | |
6 | } | |
7 | ||
8 | +int fsync_dev_lockfs(kdev_t dev) | |
9 | +{ | |
10 | + /* you are not allowed to try locking all the filesystems | |
11 | + ** on the system, your chances of getting through without | |
12 | + ** total deadlock are slim to none. | |
13 | + */ | |
14 | + if (!dev) | |
15 | + return fsync_dev(dev) ; | |
16 | + | |
17 | + sync_buffers(dev, 0); | |
18 | + | |
19 | + lock_kernel(); | |
20 | + /* note, the FS might need to start transactions to | |
21 | + ** sync the inodes, or the quota, no locking until | |
22 | + ** after these are done | |
23 | + */ | |
24 | + sync_inodes(dev); | |
25 | + DQUOT_SYNC_DEV(dev); | |
26 | + /* if inodes or quotas could be dirtied during the | |
27 | + ** sync_supers_lockfs call, the FS is responsible for getting | |
28 | + ** them on disk, without deadlocking against the lock | |
29 | + */ | |
30 | + sync_supers_lockfs(dev) ; | |
31 | + unlock_kernel(); | |
32 | + | |
33 | + return sync_buffers(dev, 1) ; | |
34 | +} | |
35 | + | |
36 | asmlinkage long sys_sync(void) | |
37 | { | |
38 | fsync_dev(0); | |
39 | diff -urNp linux-1253/fs/reiserfs/super.c linux-1255/fs/reiserfs/super.c | |
40 | --- linux-1253/fs/reiserfs/super.c | |
41 | +++ linux-1255/fs/reiserfs/super.c | |
42 | @@ -44,7 +44,7 @@ static void reiserfs_write_super_lockfs | |
43 | reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); | |
44 | journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); | |
45 | reiserfs_block_writes(&th) ; | |
46 | - journal_end(&th, s, 1) ; | |
47 | + journal_end_sync(&th, s, 1) ; | |
48 | } | |
49 | s->s_dirt = dirty; | |
50 | unlock_kernel() ; | |
51 | diff -urNp linux-1253/fs/super.c linux-1255/fs/super.c | |
52 | --- linux-1253/fs/super.c | |
53 | +++ linux-1255/fs/super.c | |
54 | @@ -38,6 +38,13 @@ | |
55 | LIST_HEAD(super_blocks); | |
56 | spinlock_t sb_lock = SPIN_LOCK_UNLOCKED; | |
57 | ||
58 | +/* | |
59 | + * lock/unlockfs grab a read lock on s_umount, but you need this lock to | |
60 | + * make sure no lockfs runs are in progress before inserting/removing | |
61 | + * supers from the list. | |
62 | + */ | |
63 | +static DECLARE_MUTEX(lockfs_sem); | |
64 | + | |
65 | /* | |
66 | * Handling of filesystem drivers list. | |
67 | * Rules: | |
68 | @@ -451,6 +458,19 @@ void drop_super(struct super_block *sb) | |
69 | put_super(sb); | |
70 | } | |
71 | ||
72 | +static void write_super_lockfs(struct super_block *sb) | |
73 | +{ | |
74 | + lock_super(sb); | |
75 | + if (sb->s_root && sb->s_op) { | |
76 | + if (sb->s_dirt && sb->s_op->write_super) | |
77 | + sb->s_op->write_super(sb); | |
78 | + if (sb->s_op->write_super_lockfs) { | |
79 | + sb->s_op->write_super_lockfs(sb); | |
80 | + } | |
81 | + } | |
82 | + unlock_super(sb); | |
83 | +} | |
84 | + | |
85 | static inline void write_super(struct super_block *sb) | |
86 | { | |
87 | lock_super(sb); | |
88 | @@ -498,6 +518,39 @@ restart: | |
89 | spin_unlock(&sb_lock); | |
90 | } | |
91 | ||
92 | +/* | |
93 | + * Note: don't check the dirty flag before waiting, we want the lock | |
94 | + * to happen every time this is called. dev must be non-zero | |
95 | + */ | |
96 | +void sync_supers_lockfs(kdev_t dev) | |
97 | +{ | |
98 | + struct super_block * sb; | |
99 | + | |
100 | + down(&lockfs_sem); | |
101 | + if (dev) { | |
102 | + sb = get_super(dev); | |
103 | + if (sb) { | |
104 | + write_super_lockfs(sb); | |
105 | + drop_super(sb); | |
106 | + } | |
107 | + } | |
108 | +} | |
109 | + | |
110 | +void unlockfs(kdev_t dev) | |
111 | +{ | |
112 | + struct super_block * sb; | |
113 | + | |
114 | + if (dev) { | |
115 | + sb = get_super(dev); | |
116 | + if (sb) { | |
117 | + if (sb->s_op && sb->s_op->unlockfs) | |
118 | + sb->s_op->unlockfs(sb) ; | |
119 | + drop_super(sb); | |
120 | + } | |
121 | + } | |
122 | + up(&lockfs_sem); | |
123 | +} | |
124 | + | |
125 | /** | |
126 | * get_super - get the superblock of a device | |
127 | * @dev: device to get the superblock for | |
128 | @@ -741,6 +794,7 @@ static struct super_block *get_sb_bdev(s | |
129 | goto out1; | |
130 | ||
131 | error = -EBUSY; | |
132 | + down(&lockfs_sem); | |
133 | restart: | |
134 | spin_lock(&sb_lock); | |
135 | ||
136 | @@ -751,11 +805,13 @@ restart: | |
137 | if (old->s_type != fs_type || | |
138 | ((flags ^ old->s_flags) & MS_RDONLY)) { | |
139 | spin_unlock(&sb_lock); | |
140 | + up(&lockfs_sem); | |
141 | destroy_super(s); | |
142 | goto out1; | |
143 | } | |
144 | if (!grab_super(old)) | |
145 | goto restart; | |
146 | + up(&lockfs_sem); | |
147 | destroy_super(s); | |
148 | blkdev_put(bdev, BDEV_FS); | |
149 | path_release(&nd); | |
150 | @@ -765,6 +821,7 @@ restart: | |
151 | s->s_bdev = bdev; | |
152 | s->s_flags = flags; | |
153 | insert_super(s, fs_type); | |
154 | + up(&lockfs_sem); | |
155 | if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) | |
156 | goto Einval; | |
157 | s->s_flags |= MS_ACTIVE; | |
158 | @@ -872,7 +929,10 @@ void kill_super(struct super_block *sb) | |
159 | if (!deactivate_super(sb)) | |
160 | return; | |
161 | ||
162 | + down(&lockfs_sem); | |
163 | down_write(&sb->s_umount); | |
164 | + up(&lockfs_sem); | |
165 | + | |
166 | sb->s_root = NULL; | |
167 | /* Need to clean after the sucker */ | |
168 | if (fs->fs_flags & FS_LITTER) | |
169 | diff -urNp linux-1253/include/linux/fs.h linux-1255/include/linux/fs.h | |
170 | --- linux-1253/include/linux/fs.h | |
171 | +++ linux-1255/include/linux/fs.h | |
172 | @@ -1275,6 +1275,7 @@ extern void write_inode_now(struct inode | |
173 | extern int sync_buffers(kdev_t, int); | |
174 | extern void sync_dev(kdev_t); | |
175 | extern int fsync_dev(kdev_t); | |
176 | +extern int fsync_dev_lockfs(kdev_t); | |
177 | extern int fsync_super(struct super_block *); | |
178 | extern int fsync_no_super(kdev_t); | |
179 | extern void sync_inodes_sb(struct super_block *); | |
180 | @@ -1291,6 +1292,8 @@ extern int inode_has_buffers(struct inod | |
181 | extern int filemap_fdatasync(struct address_space *); | |
182 | extern int filemap_fdatawait(struct address_space *); | |
183 | extern void sync_supers(kdev_t); | |
184 | +extern void sync_supers_lockfs(kdev_t); | |
185 | +extern void unlockfs(kdev_t); | |
186 | extern int bmap(struct inode *, int); | |
187 | extern int notify_change(struct dentry *, struct iattr *); | |
188 | extern int permission(struct inode *, int); | |
189 | diff -urNp linux-1253/kernel/ksyms.c linux-1255/kernel/ksyms.c | |
190 | --- linux-1253/kernel/ksyms.c | |
191 | +++ linux-1255/kernel/ksyms.c | |
192 | @@ -208,6 +208,8 @@ EXPORT_SYMBOL(invalidate_device); | |
193 | EXPORT_SYMBOL(invalidate_inode_pages); | |
194 | EXPORT_SYMBOL(truncate_inode_pages); | |
195 | EXPORT_SYMBOL(fsync_dev); | |
196 | +EXPORT_SYMBOL_GPL(fsync_dev_lockfs); | |
197 | +EXPORT_SYMBOL_GPL(unlockfs); | |
198 | EXPORT_SYMBOL(fsync_no_super); | |
199 | EXPORT_SYMBOL(permission); | |
200 | EXPORT_SYMBOL(vfs_permission); |