658 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * linux/fs/ufs/ufs_dir.c4 *5 * Copyright (C) 19966 * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)7 * Laboratory for Computer Science Research Computing Facility8 * Rutgers, The State University of New Jersey9 *10 * swab support by Francois-Rene Rideau <fare@tunes.org> 1997040611 *12 * 4.4BSD (FreeBSD) support added on February 1st 1998 by13 * Niels Kristian Bech Jensen <nkbj@image.dk> partially based14 * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.15 *16 * Migration to usage of "page cache" on May 2006 by17 * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.18 */19 20#include <linux/time.h>21#include <linux/fs.h>22#include <linux/swap.h>23#include <linux/iversion.h>24 25#include "ufs_fs.h"26#include "ufs.h"27#include "swab.h"28#include "util.h"29 30/*31 * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.32 *33 * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller.34 */35static inline int ufs_match(struct super_block *sb, int len,36 const unsigned char *name, struct ufs_dir_entry *de)37{38 if (len != ufs_get_de_namlen(sb, de))39 return 0;40 if (!de->d_ino)41 return 0;42 return !memcmp(name, de->d_name, len);43}44 45static void ufs_commit_chunk(struct folio *folio, loff_t pos, unsigned len)46{47 struct address_space *mapping = folio->mapping;48 struct inode *dir = mapping->host;49 50 inode_inc_iversion(dir);51 block_write_end(NULL, mapping, pos, len, len, folio, NULL);52 if (pos+len > dir->i_size) {53 i_size_write(dir, pos+len);54 mark_inode_dirty(dir);55 }56 folio_unlock(folio);57}58 59static int ufs_handle_dirsync(struct inode *dir)60{61 int err;62 63 err = filemap_write_and_wait(dir->i_mapping);64 if (!err)65 err = sync_inode_metadata(dir, 1);66 return err;67}68 69ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr)70{71 ino_t res = 0;72 struct ufs_dir_entry *de;73 struct folio *folio;74 75 de = ufs_find_entry(dir, qstr, &folio);76 if (de) {77 res = fs32_to_cpu(dir->i_sb, de->d_ino);78 folio_release_kmap(folio, de);79 }80 return res;81}82 83 84/* Releases the page */85void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,86 struct folio *folio, struct inode *inode,87 bool update_times)88{89 loff_t pos = folio_pos(folio) + offset_in_folio(folio, de);90 unsigned len = fs16_to_cpu(dir->i_sb, de->d_reclen);91 int err;92 93 folio_lock(folio);94 err = ufs_prepare_chunk(folio, pos, len);95 BUG_ON(err);96 97 de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);98 ufs_set_de_type(dir->i_sb, de, inode->i_mode);99 100 ufs_commit_chunk(folio, pos, len);101 folio_release_kmap(folio, de);102 if (update_times)103 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));104 mark_inode_dirty(dir);105 ufs_handle_dirsync(dir);106}107 108static bool ufs_check_folio(struct folio *folio, char *kaddr)109{110 struct inode *dir = folio->mapping->host;111 struct super_block *sb = dir->i_sb;112 unsigned offs, rec_len;113 unsigned limit = folio_size(folio);114 const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1;115 struct ufs_dir_entry *p;116 char *error;117 118 if (dir->i_size < folio_pos(folio) + limit) {119 limit = offset_in_folio(folio, dir->i_size);120 if (limit & chunk_mask)121 goto Ebadsize;122 if (!limit)123 goto out;124 }125 for (offs = 0; offs <= limit - UFS_DIR_REC_LEN(1); offs += rec_len) {126 p = (struct ufs_dir_entry *)(kaddr + offs);127 rec_len = fs16_to_cpu(sb, p->d_reclen);128 129 if (rec_len < UFS_DIR_REC_LEN(1))130 goto Eshort;131 if (rec_len & 3)132 goto Ealign;133 if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))134 goto Enamelen;135 if (((offs + rec_len - 1) ^ offs) & ~chunk_mask)136 goto Espan;137 if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *138 UFS_SB(sb)->s_uspi->s_ncg))139 goto Einumber;140 }141 if (offs != limit)142 goto Eend;143out:144 folio_set_checked(folio);145 return true;146 147 /* Too bad, we had an error */148 149Ebadsize:150 ufs_error(sb, __func__,151 "size of directory #%lu is not a multiple of chunk size",152 dir->i_ino153 );154 goto fail;155Eshort:156 error = "rec_len is smaller than minimal";157 goto bad_entry;158Ealign:159 error = "unaligned directory entry";160 goto bad_entry;161Enamelen:162 error = "rec_len is too small for name_len";163 goto bad_entry;164Espan:165 error = "directory entry across blocks";166 goto bad_entry;167Einumber:168 error = "inode out of bounds";169bad_entry:170 ufs_error(sb, __func__, "bad entry in directory #%lu: %s - "171 "offset=%llu, rec_len=%d, name_len=%d",172 dir->i_ino, error, folio_pos(folio) + offs,173 rec_len, ufs_get_de_namlen(sb, p));174 goto fail;175Eend:176 p = (struct ufs_dir_entry *)(kaddr + offs);177 ufs_error(sb, __func__,178 "entry in directory #%lu spans the page boundary"179 "offset=%llu",180 dir->i_ino, folio_pos(folio) + offs);181fail:182 return false;183}184 185static void *ufs_get_folio(struct inode *dir, unsigned long n,186 struct folio **foliop)187{188 struct address_space *mapping = dir->i_mapping;189 struct folio *folio = read_mapping_folio(mapping, n, NULL);190 void *kaddr;191 192 if (IS_ERR(folio))193 return ERR_CAST(folio);194 kaddr = kmap_local_folio(folio, 0);195 if (unlikely(!folio_test_checked(folio))) {196 if (!ufs_check_folio(folio, kaddr))197 goto fail;198 }199 *foliop = folio;200 return kaddr;201 202fail:203 folio_release_kmap(folio, kaddr);204 return ERR_PTR(-EIO);205}206 207/*208 * Return the offset into page `page_nr' of the last valid209 * byte in that page, plus one.210 */211static unsigned212ufs_last_byte(struct inode *inode, unsigned long page_nr)213{214 unsigned last_byte = inode->i_size;215 216 last_byte -= page_nr << PAGE_SHIFT;217 if (last_byte > PAGE_SIZE)218 last_byte = PAGE_SIZE;219 return last_byte;220}221 222static inline struct ufs_dir_entry *223ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)224{225 return (struct ufs_dir_entry *)((char *)p +226 fs16_to_cpu(sb, p->d_reclen));227}228 229struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct folio **foliop)230{231 struct ufs_dir_entry *de = ufs_get_folio(dir, 0, foliop);232 233 if (!IS_ERR(de))234 return ufs_next_entry(dir->i_sb, de);235 236 return NULL;237}238 239/*240 * ufs_find_entry()241 *242 * finds an entry in the specified directory with the wanted name. It243 * returns the page in which the entry was found, and the entry itself244 * (as a parameter - res_dir). Page is returned mapped and unlocked.245 * Entry is guaranteed to be valid.246 */247struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,248 struct folio **foliop)249{250 struct super_block *sb = dir->i_sb;251 const unsigned char *name = qstr->name;252 int namelen = qstr->len;253 unsigned reclen = UFS_DIR_REC_LEN(namelen);254 unsigned long start, n;255 unsigned long npages = dir_pages(dir);256 struct ufs_inode_info *ui = UFS_I(dir);257 struct ufs_dir_entry *de;258 259 UFSD("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen);260 261 if (npages == 0 || namelen > UFS_MAXNAMLEN)262 goto out;263 264 start = ui->i_dir_start_lookup;265 266 if (start >= npages)267 start = 0;268 n = start;269 do {270 char *kaddr = ufs_get_folio(dir, n, foliop);271 272 if (!IS_ERR(kaddr)) {273 de = (struct ufs_dir_entry *)kaddr;274 kaddr += ufs_last_byte(dir, n) - reclen;275 while ((char *) de <= kaddr) {276 if (ufs_match(sb, namelen, name, de))277 goto found;278 de = ufs_next_entry(sb, de);279 }280 folio_release_kmap(*foliop, kaddr);281 }282 if (++n >= npages)283 n = 0;284 } while (n != start);285out:286 return NULL;287 288found:289 ui->i_dir_start_lookup = n;290 return de;291}292 293/*294 * Parent is locked.295 */296int ufs_add_link(struct dentry *dentry, struct inode *inode)297{298 struct inode *dir = d_inode(dentry->d_parent);299 const unsigned char *name = dentry->d_name.name;300 int namelen = dentry->d_name.len;301 struct super_block *sb = dir->i_sb;302 unsigned reclen = UFS_DIR_REC_LEN(namelen);303 const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;304 unsigned short rec_len, name_len;305 struct folio *folio = NULL;306 struct ufs_dir_entry *de;307 unsigned long npages = dir_pages(dir);308 unsigned long n;309 loff_t pos;310 int err;311 312 UFSD("ENTER, name %s, namelen %u\n", name, namelen);313 314 /*315 * We take care of directory expansion in the same loop.316 * This code plays outside i_size, so it locks the folio317 * to protect that region.318 */319 for (n = 0; n <= npages; n++) {320 char *kaddr = ufs_get_folio(dir, n, &folio);321 char *dir_end;322 323 if (IS_ERR(kaddr))324 return PTR_ERR(kaddr);325 folio_lock(folio);326 dir_end = kaddr + ufs_last_byte(dir, n);327 de = (struct ufs_dir_entry *)kaddr;328 kaddr += folio_size(folio) - reclen;329 while ((char *)de <= kaddr) {330 if ((char *)de == dir_end) {331 /* We hit i_size */332 name_len = 0;333 rec_len = chunk_size;334 de->d_reclen = cpu_to_fs16(sb, chunk_size);335 de->d_ino = 0;336 goto got_it;337 }338 if (de->d_reclen == 0) {339 ufs_error(dir->i_sb, __func__,340 "zero-length directory entry");341 err = -EIO;342 goto out_unlock;343 }344 err = -EEXIST;345 if (ufs_match(sb, namelen, name, de))346 goto out_unlock;347 name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de));348 rec_len = fs16_to_cpu(sb, de->d_reclen);349 if (!de->d_ino && rec_len >= reclen)350 goto got_it;351 if (rec_len >= name_len + reclen)352 goto got_it;353 de = (struct ufs_dir_entry *) ((char *) de + rec_len);354 }355 folio_unlock(folio);356 folio_release_kmap(folio, kaddr);357 }358 BUG();359 return -EINVAL;360 361got_it:362 pos = folio_pos(folio) + offset_in_folio(folio, de);363 err = ufs_prepare_chunk(folio, pos, rec_len);364 if (err)365 goto out_unlock;366 if (de->d_ino) {367 struct ufs_dir_entry *de1 =368 (struct ufs_dir_entry *) ((char *) de + name_len);369 de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len);370 de->d_reclen = cpu_to_fs16(sb, name_len);371 372 de = de1;373 }374 375 ufs_set_de_namlen(sb, de, namelen);376 memcpy(de->d_name, name, namelen + 1);377 de->d_ino = cpu_to_fs32(sb, inode->i_ino);378 ufs_set_de_type(sb, de, inode->i_mode);379 380 ufs_commit_chunk(folio, pos, rec_len);381 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));382 383 mark_inode_dirty(dir);384 err = ufs_handle_dirsync(dir);385 /* OFFSET_CACHE */386out_put:387 folio_release_kmap(folio, de);388 return err;389out_unlock:390 folio_unlock(folio);391 goto out_put;392}393 394static inline unsigned395ufs_validate_entry(struct super_block *sb, char *base,396 unsigned offset, unsigned mask)397{398 struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);399 struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));400 while ((char*)p < (char*)de)401 p = ufs_next_entry(sb, p);402 return (char *)p - base;403}404 405 406/*407 * This is blatantly stolen from ext2fs408 */409static int410ufs_readdir(struct file *file, struct dir_context *ctx)411{412 loff_t pos = ctx->pos;413 struct inode *inode = file_inode(file);414 struct super_block *sb = inode->i_sb;415 unsigned int offset = pos & ~PAGE_MASK;416 unsigned long n = pos >> PAGE_SHIFT;417 unsigned long npages = dir_pages(inode);418 unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);419 bool need_revalidate = !inode_eq_iversion(inode, *(u64 *)file->private_data);420 unsigned flags = UFS_SB(sb)->s_flags;421 422 UFSD("BEGIN\n");423 424 if (pos > inode->i_size - UFS_DIR_REC_LEN(1))425 return 0;426 427 for ( ; n < npages; n++, offset = 0) {428 struct ufs_dir_entry *de;429 struct folio *folio;430 char *kaddr = ufs_get_folio(inode, n, &folio);431 char *limit;432 433 if (IS_ERR(kaddr)) {434 ufs_error(sb, __func__,435 "bad page in #%lu",436 inode->i_ino);437 ctx->pos += PAGE_SIZE - offset;438 return PTR_ERR(kaddr);439 }440 if (unlikely(need_revalidate)) {441 if (offset) {442 offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask);443 ctx->pos = (n<<PAGE_SHIFT) + offset;444 }445 *(u64 *)file->private_data = inode_query_iversion(inode);446 need_revalidate = false;447 }448 de = (struct ufs_dir_entry *)(kaddr+offset);449 limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);450 for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {451 if (de->d_ino) {452 unsigned char d_type = DT_UNKNOWN;453 454 UFSD("filldir(%s,%u)\n", de->d_name,455 fs32_to_cpu(sb, de->d_ino));456 UFSD("namlen %u\n", ufs_get_de_namlen(sb, de));457 458 if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)459 d_type = de->d_u.d_44.d_type;460 461 if (!dir_emit(ctx, de->d_name,462 ufs_get_de_namlen(sb, de),463 fs32_to_cpu(sb, de->d_ino),464 d_type)) {465 folio_release_kmap(folio, de);466 return 0;467 }468 }469 ctx->pos += fs16_to_cpu(sb, de->d_reclen);470 }471 folio_release_kmap(folio, kaddr);472 }473 return 0;474}475 476 477/*478 * ufs_delete_entry deletes a directory entry by merging it with the479 * previous entry.480 */481int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,482 struct folio *folio)483{484 struct super_block *sb = inode->i_sb;485 size_t from, to;486 char *kaddr;487 loff_t pos;488 struct ufs_dir_entry *de, *pde = NULL;489 int err;490 491 UFSD("ENTER\n");492 493 from = offset_in_folio(folio, dir);494 to = from + fs16_to_cpu(sb, dir->d_reclen);495 kaddr = (char *)dir - from;496 from &= ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);497 de = (struct ufs_dir_entry *) (kaddr + from);498 499 UFSD("ino %u, reclen %u, namlen %u, name %s\n",500 fs32_to_cpu(sb, de->d_ino),501 fs16_to_cpu(sb, de->d_reclen),502 ufs_get_de_namlen(sb, de), de->d_name);503 504 while ((char*)de < (char*)dir) {505 if (de->d_reclen == 0) {506 ufs_error(inode->i_sb, __func__,507 "zero-length directory entry");508 err = -EIO;509 goto out;510 }511 pde = de;512 de = ufs_next_entry(sb, de);513 }514 if (pde)515 from = offset_in_folio(folio, pde);516 pos = folio_pos(folio) + from;517 folio_lock(folio);518 err = ufs_prepare_chunk(folio, pos, to - from);519 BUG_ON(err);520 if (pde)521 pde->d_reclen = cpu_to_fs16(sb, to - from);522 dir->d_ino = 0;523 ufs_commit_chunk(folio, pos, to - from);524 inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));525 mark_inode_dirty(inode);526 err = ufs_handle_dirsync(inode);527out:528 folio_release_kmap(folio, kaddr);529 UFSD("EXIT\n");530 return err;531}532 533int ufs_make_empty(struct inode * inode, struct inode *dir)534{535 struct super_block * sb = dir->i_sb;536 struct address_space *mapping = inode->i_mapping;537 struct folio *folio = filemap_grab_folio(mapping, 0);538 const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;539 struct ufs_dir_entry * de;540 int err;541 char *kaddr;542 543 if (IS_ERR(folio))544 return PTR_ERR(folio);545 546 err = ufs_prepare_chunk(folio, 0, chunk_size);547 if (err) {548 folio_unlock(folio);549 goto fail;550 }551 552 kaddr = kmap_local_folio(folio, 0);553 memset(kaddr, 0, folio_size(folio));554 555 de = (struct ufs_dir_entry *)kaddr;556 557 de->d_ino = cpu_to_fs32(sb, inode->i_ino);558 ufs_set_de_type(sb, de, inode->i_mode);559 ufs_set_de_namlen(sb, de, 1);560 de->d_reclen = cpu_to_fs16(sb, UFS_DIR_REC_LEN(1));561 strcpy (de->d_name, ".");562 de = (struct ufs_dir_entry *)563 ((char *)de + fs16_to_cpu(sb, de->d_reclen));564 de->d_ino = cpu_to_fs32(sb, dir->i_ino);565 ufs_set_de_type(sb, de, dir->i_mode);566 de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1));567 ufs_set_de_namlen(sb, de, 2);568 strcpy (de->d_name, "..");569 kunmap_local(kaddr);570 571 ufs_commit_chunk(folio, 0, chunk_size);572 err = ufs_handle_dirsync(inode);573fail:574 folio_put(folio);575 return err;576}577 578/*579 * routine to check that the specified directory is empty (for rmdir)580 */581int ufs_empty_dir(struct inode * inode)582{583 struct super_block *sb = inode->i_sb;584 struct folio *folio;585 char *kaddr;586 unsigned long i, npages = dir_pages(inode);587 588 for (i = 0; i < npages; i++) {589 struct ufs_dir_entry *de;590 591 kaddr = ufs_get_folio(inode, i, &folio);592 if (IS_ERR(kaddr))593 continue;594 595 de = (struct ufs_dir_entry *)kaddr;596 kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1);597 598 while ((char *)de <= kaddr) {599 if (de->d_reclen == 0) {600 ufs_error(inode->i_sb, __func__,601 "zero-length directory entry: "602 "kaddr=%p, de=%p\n", kaddr, de);603 goto not_empty;604 }605 if (de->d_ino) {606 u16 namelen=ufs_get_de_namlen(sb, de);607 /* check for . and .. */608 if (de->d_name[0] != '.')609 goto not_empty;610 if (namelen > 2)611 goto not_empty;612 if (namelen < 2) {613 if (inode->i_ino !=614 fs32_to_cpu(sb, de->d_ino))615 goto not_empty;616 } else if (de->d_name[1] != '.')617 goto not_empty;618 }619 de = ufs_next_entry(sb, de);620 }621 folio_release_kmap(folio, kaddr);622 }623 return 1;624 625not_empty:626 folio_release_kmap(folio, kaddr);627 return 0;628}629 630static int ufs_dir_open(struct inode *inode, struct file *file)631{632 file->private_data = kzalloc(sizeof(u64), GFP_KERNEL);633 if (!file->private_data)634 return -ENOMEM;635 return 0;636}637 638static int ufs_dir_release(struct inode *inode, struct file *file)639{640 kfree(file->private_data);641 return 0;642}643 644static loff_t ufs_dir_llseek(struct file *file, loff_t offset, int whence)645{646 return generic_llseek_cookie(file, offset, whence,647 (u64 *)file->private_data);648}649 650const struct file_operations ufs_dir_operations = {651 .open = ufs_dir_open,652 .release = ufs_dir_release,653 .read = generic_read_dir,654 .iterate_shared = ufs_readdir,655 .fsync = generic_file_fsync,656 .llseek = ufs_dir_llseek,657};658