Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'work.sysv' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull sysv updates from Al Viro:
"Fabio's 'switch to kmap_local_page()' patchset (originally after the
ext2 counterpart, with a lot of cleaning up done to it; as the matter
of fact, ext2 side is in need of similar cleanups - calling
conventions there are bloody awful).

Plus the equivalents of minix stuff..."

* 'work.sysv' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
sysv: fix handling of delete_entry and set_link failures
fs/sysv: Replace kmap() with kmap_local_page()
fs/sysv: Use dir_put_page() in sysv_rename()
fs/sysv: Change the signature of dir_get_page()
fs/sysv: Use the offset_in_page() helper
sysv: don't flush page immediately for DIRSYNC directories

+111 -88
+87 -67
fs/sysv/dir.c
··· 28 28 .fsync = generic_file_fsync, 29 29 }; 30 30 31 - static inline void dir_put_page(struct page *page) 31 + inline void dir_put_page(struct page *page, void *page_addr) 32 32 { 33 - kunmap(page); 33 + kunmap_local((void *)((unsigned long)page_addr & PAGE_MASK)); 34 34 put_page(page); 35 35 } 36 36 37 - static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len) 37 + static void dir_commit_chunk(struct page *page, loff_t pos, unsigned len) 38 38 { 39 39 struct address_space *mapping = page->mapping; 40 40 struct inode *dir = mapping->host; 41 - int err = 0; 42 41 43 42 block_write_end(NULL, mapping, pos, len, len, page, NULL); 44 43 if (pos+len > dir->i_size) { 45 44 i_size_write(dir, pos+len); 46 45 mark_inode_dirty(dir); 47 46 } 48 - if (IS_DIRSYNC(dir)) 49 - err = write_one_page(page); 50 - else 51 - unlock_page(page); 47 + unlock_page(page); 48 + } 49 + 50 + static int sysv_handle_dirsync(struct inode *dir) 51 + { 52 + int err; 53 + 54 + err = filemap_write_and_wait(dir->i_mapping); 55 + if (!err) 56 + err = sync_inode_metadata(dir, 1); 52 57 return err; 53 58 } 54 59 55 - static struct page * dir_get_page(struct inode *dir, unsigned long n) 60 + /* 61 + * Calls to dir_get_page()/dir_put_page() must be nested according to the 62 + * rules documented in mm/highmem.rst. 63 + * 64 + * NOTE: sysv_find_entry() and sysv_dotdot() act as calls to dir_get_page() 65 + * and must be treated accordingly for nesting purposes. 66 + */ 67 + static void *dir_get_page(struct inode *dir, unsigned long n, struct page **p) 56 68 { 57 69 struct address_space *mapping = dir->i_mapping; 58 70 struct page *page = read_mapping_page(mapping, n, NULL); 59 - if (!IS_ERR(page)) 60 - kmap(page); 61 - return page; 71 + if (IS_ERR(page)) 72 + return ERR_CAST(page); 73 + *p = page; 74 + return kmap_local_page(page); 62 75 } 63 76 64 77 static int sysv_readdir(struct file *file, struct dir_context *ctx) ··· 93 80 for ( ; n < npages; n++, offset = 0) { 94 81 char *kaddr, *limit; 95 82 struct sysv_dir_entry *de; 96 - struct page *page = dir_get_page(inode, n); 83 + struct page *page; 97 84 98 - if (IS_ERR(page)) 85 + kaddr = dir_get_page(inode, n, &page); 86 + if (IS_ERR(kaddr)) 99 87 continue; 100 - kaddr = (char *)page_address(page); 101 88 de = (struct sysv_dir_entry *)(kaddr+offset); 102 89 limit = kaddr + PAGE_SIZE - SYSV_DIRSIZE; 103 90 for ( ;(char*)de <= limit; de++, ctx->pos += sizeof(*de)) { ··· 109 96 if (!dir_emit(ctx, name, strnlen(name,SYSV_NAMELEN), 110 97 fs16_to_cpu(SYSV_SB(sb), de->inode), 111 98 DT_UNKNOWN)) { 112 - dir_put_page(page); 99 + dir_put_page(page, kaddr); 113 100 return 0; 114 101 } 115 102 } 116 - dir_put_page(page); 103 + dir_put_page(page, kaddr); 117 104 } 118 105 return 0; 119 106 } ··· 136 123 * returns the cache buffer in which the entry was found, and the entry 137 124 * itself (as a parameter - res_dir). It does NOT read the inode of the 138 125 * entry - you'll have to do that yourself if you want to. 126 + * 127 + * On Success dir_put_page() should be called on *res_page. 128 + * 129 + * sysv_find_entry() acts as a call to dir_get_page() and must be treated 130 + * accordingly for nesting purposes. 139 131 */ 140 132 struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page) 141 133 { ··· 160 142 n = start; 161 143 162 144 do { 163 - char *kaddr; 164 - page = dir_get_page(dir, n); 165 - if (!IS_ERR(page)) { 166 - kaddr = (char*)page_address(page); 167 - de = (struct sysv_dir_entry *) kaddr; 145 + char *kaddr = dir_get_page(dir, n, &page); 146 + 147 + if (!IS_ERR(kaddr)) { 148 + de = (struct sysv_dir_entry *)kaddr; 168 149 kaddr += PAGE_SIZE - SYSV_DIRSIZE; 169 150 for ( ; (char *) de <= kaddr ; de++) { 170 151 if (!de->inode) ··· 172 155 name, de->name)) 173 156 goto found; 174 157 } 175 - dir_put_page(page); 158 + dir_put_page(page, kaddr); 176 159 } 177 160 178 161 if (++n >= npages) ··· 202 185 203 186 /* We take care of directory expansion in the same loop */ 204 187 for (n = 0; n <= npages; n++) { 205 - page = dir_get_page(dir, n); 206 - err = PTR_ERR(page); 207 - if (IS_ERR(page)) 208 - goto out; 209 - kaddr = (char*)page_address(page); 188 + kaddr = dir_get_page(dir, n, &page); 189 + if (IS_ERR(kaddr)) 190 + return PTR_ERR(kaddr); 210 191 de = (struct sysv_dir_entry *)kaddr; 211 192 kaddr += PAGE_SIZE - SYSV_DIRSIZE; 212 193 while ((char *)de <= kaddr) { ··· 215 200 goto out_page; 216 201 de++; 217 202 } 218 - dir_put_page(page); 203 + dir_put_page(page, kaddr); 219 204 } 220 205 BUG(); 221 206 return -EINVAL; 222 207 223 208 got_it: 224 - pos = page_offset(page) + 225 - (char*)de - (char*)page_address(page); 209 + pos = page_offset(page) + offset_in_page(de); 226 210 lock_page(page); 227 211 err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE); 228 212 if (err) ··· 229 215 memcpy (de->name, name, namelen); 230 216 memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2); 231 217 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); 232 - err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); 218 + dir_commit_chunk(page, pos, SYSV_DIRSIZE); 233 219 dir->i_mtime = dir->i_ctime = current_time(dir); 234 220 mark_inode_dirty(dir); 221 + err = sysv_handle_dirsync(dir); 235 222 out_page: 236 - dir_put_page(page); 237 - out: 223 + dir_put_page(page, kaddr); 238 224 return err; 239 225 out_unlock: 240 226 unlock_page(page); ··· 244 230 int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) 245 231 { 246 232 struct inode *inode = page->mapping->host; 247 - char *kaddr = (char*)page_address(page); 248 - loff_t pos = page_offset(page) + (char *)de - kaddr; 233 + loff_t pos = page_offset(page) + offset_in_page(de); 249 234 int err; 250 235 251 236 lock_page(page); 252 237 err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE); 253 - BUG_ON(err); 238 + if (err) { 239 + unlock_page(page); 240 + return err; 241 + } 254 242 de->inode = 0; 255 - err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); 256 - dir_put_page(page); 243 + dir_commit_chunk(page, pos, SYSV_DIRSIZE); 257 244 inode->i_ctime = inode->i_mtime = current_time(inode); 258 245 mark_inode_dirty(inode); 259 - return err; 246 + return sysv_handle_dirsync(inode); 260 247 } 261 248 262 249 int sysv_make_empty(struct inode *inode, struct inode *dir) ··· 274 259 unlock_page(page); 275 260 goto fail; 276 261 } 277 - kmap(page); 278 - 279 - base = (char*)page_address(page); 262 + base = kmap_local_page(page); 280 263 memset(base, 0, PAGE_SIZE); 281 264 282 265 de = (struct sysv_dir_entry *) base; ··· 284 271 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino); 285 272 strcpy(de->name,".."); 286 273 287 - kunmap(page); 288 - err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE); 274 + kunmap_local(base); 275 + dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE); 276 + err = sysv_handle_dirsync(inode); 289 277 fail: 290 278 put_page(page); 291 279 return err; ··· 300 286 struct super_block *sb = inode->i_sb; 301 287 struct page *page = NULL; 302 288 unsigned long i, npages = dir_pages(inode); 289 + char *kaddr; 303 290 304 291 for (i = 0; i < npages; i++) { 305 - char *kaddr; 306 - struct sysv_dir_entry * de; 307 - page = dir_get_page(inode, i); 292 + struct sysv_dir_entry *de; 308 293 309 - if (IS_ERR(page)) 294 + kaddr = dir_get_page(inode, i, &page); 295 + if (IS_ERR(kaddr)) 310 296 continue; 311 297 312 - kaddr = (char *)page_address(page); 313 298 de = (struct sysv_dir_entry *)kaddr; 314 299 kaddr += PAGE_SIZE-SYSV_DIRSIZE; 315 300 ··· 327 314 if (de->name[1] != '.' || de->name[2]) 328 315 goto not_empty; 329 316 } 330 - dir_put_page(page); 317 + dir_put_page(page, kaddr); 331 318 } 332 319 return 1; 333 320 334 321 not_empty: 335 - dir_put_page(page); 322 + dir_put_page(page, kaddr); 336 323 return 0; 337 324 } 338 325 339 326 /* Releases the page */ 340 - void sysv_set_link(struct sysv_dir_entry *de, struct page *page, 327 + int sysv_set_link(struct sysv_dir_entry *de, struct page *page, 341 328 struct inode *inode) 342 329 { 343 330 struct inode *dir = page->mapping->host; 344 - loff_t pos = page_offset(page) + 345 - (char *)de-(char*)page_address(page); 331 + loff_t pos = page_offset(page) + offset_in_page(de); 346 332 int err; 347 333 348 334 lock_page(page); 349 335 err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE); 350 - BUG_ON(err); 336 + if (err) { 337 + unlock_page(page); 338 + return err; 339 + } 351 340 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); 352 - err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); 353 - dir_put_page(page); 341 + dir_commit_chunk(page, pos, SYSV_DIRSIZE); 354 342 dir->i_mtime = dir->i_ctime = current_time(dir); 355 343 mark_inode_dirty(dir); 344 + return sysv_handle_dirsync(inode); 356 345 } 357 346 358 - struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p) 347 + /* 348 + * Calls to dir_get_page()/dir_put_page() must be nested according to the 349 + * rules documented in mm/highmem.rst. 350 + * 351 + * sysv_dotdot() acts as a call to dir_get_page() and must be treated 352 + * accordingly for nesting purposes. 353 + */ 354 + struct sysv_dir_entry *sysv_dotdot(struct inode *dir, struct page **p) 359 355 { 360 - struct page *page = dir_get_page(dir, 0); 361 - struct sysv_dir_entry *de = NULL; 356 + struct sysv_dir_entry *de = dir_get_page(dir, 0, p); 362 357 363 - if (!IS_ERR(page)) { 364 - de = (struct sysv_dir_entry*) page_address(page) + 1; 365 - *p = page; 366 - } 367 - return de; 358 + if (IS_ERR(de)) 359 + return NULL; 360 + /* ".." is the second directory entry */ 361 + return de + 1; 368 362 } 369 363 370 364 ino_t sysv_inode_by_name(struct dentry *dentry) ··· 382 362 383 363 if (de) { 384 364 res = fs16_to_cpu(SYSV_SB(dentry->d_sb), de->inode); 385 - dir_put_page(page); 365 + dir_put_page(page, de); 386 366 } 387 367 return res; 388 368 }
+22 -20
fs/sysv/namei.c
··· 153 153 struct inode * inode = d_inode(dentry); 154 154 struct page * page; 155 155 struct sysv_dir_entry * de; 156 - int err = -ENOENT; 156 + int err; 157 157 158 158 de = sysv_find_entry(dentry, &page); 159 159 if (!de) 160 - goto out; 160 + return -ENOENT; 161 161 162 - err = sysv_delete_entry (de, page); 163 - if (err) 164 - goto out; 165 - 166 - inode->i_ctime = dir->i_ctime; 167 - inode_dec_link_count(inode); 168 - out: 162 + err = sysv_delete_entry(de, page); 163 + if (!err) { 164 + inode->i_ctime = dir->i_ctime; 165 + inode_dec_link_count(inode); 166 + } 167 + dir_put_page(page, de); 169 168 return err; 170 169 } 171 170 ··· 226 227 new_de = sysv_find_entry(new_dentry, &new_page); 227 228 if (!new_de) 228 229 goto out_dir; 229 - sysv_set_link(new_de, new_page, old_inode); 230 + err = sysv_set_link(new_de, new_page, old_inode); 231 + dir_put_page(new_page, new_de); 232 + if (err) 233 + goto out_dir; 230 234 new_inode->i_ctime = current_time(new_inode); 231 235 if (dir_de) 232 236 drop_nlink(new_inode); ··· 242 240 inode_inc_link_count(new_dir); 243 241 } 244 242 245 - sysv_delete_entry(old_de, old_page); 243 + err = sysv_delete_entry(old_de, old_page); 244 + if (err) 245 + goto out_dir; 246 + 246 247 mark_inode_dirty(old_inode); 247 248 248 249 if (dir_de) { 249 - sysv_set_link(dir_de, dir_page, new_dir); 250 - inode_dec_link_count(old_dir); 250 + err = sysv_set_link(dir_de, dir_page, new_dir); 251 + if (!err) 252 + inode_dec_link_count(old_dir); 251 253 } 252 - return 0; 253 254 254 255 out_dir: 255 - if (dir_de) { 256 - kunmap(dir_page); 257 - put_page(dir_page); 258 - } 256 + if (dir_de) 257 + dir_put_page(dir_page, dir_de); 259 258 out_old: 260 - kunmap(old_page); 261 - put_page(old_page); 259 + dir_put_page(old_page, old_de); 262 260 out: 263 261 return err; 264 262 }
+2 -1
fs/sysv/sysv.h
··· 148 148 149 149 150 150 /* dir.c */ 151 + extern void dir_put_page(struct page *page, void *vaddr); 151 152 extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **); 152 153 extern int sysv_add_link(struct dentry *, struct inode *); 153 154 extern int sysv_delete_entry(struct sysv_dir_entry *, struct page *); 154 155 extern int sysv_make_empty(struct inode *, struct inode *); 155 156 extern int sysv_empty_dir(struct inode *); 156 - extern void sysv_set_link(struct sysv_dir_entry *, struct page *, 157 + extern int sysv_set_link(struct sysv_dir_entry *, struct page *, 157 158 struct inode *); 158 159 extern struct sysv_dir_entry *sysv_dotdot(struct inode *, struct page **); 159 160 extern ino_t sysv_inode_by_name(struct dentry *);