The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/affs/inode.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/affs/inode.c
    3  *
    4  *  (c) 1996  Hans-Joachim Widmaier - Rewritten
    5  *
    6  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
    7  *
    8  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
    9  *
   10  *  (C) 1991  Linus Torvalds - minix filesystem
   11  */
   12 
   13 #include <asm/div64.h>
   14 #include <linux/errno.h>
   15 #include <linux/fs.h>
   16 #include <linux/slab.h>
   17 #include <linux/stat.h>
   18 #include <linux/sched.h>
   19 #include <linux/affs_fs.h>
   20 #include <linux/kernel.h>
   21 #include <linux/mm.h>
   22 #include <linux/string.h>
   23 #include <linux/locks.h>
   24 #include <linux/genhd.h>
   25 #include <linux/amigaffs.h>
   26 #include <linux/major.h>
   27 #include <linux/blkdev.h>
   28 #include <linux/init.h>
   29 #include <linux/smp_lock.h>
   30 #include <asm/system.h>
   31 #include <asm/uaccess.h>
   32 #include <linux/module.h>
   33 
   34 extern struct inode_operations affs_symlink_inode_operations;
   35 extern struct timezone sys_tz;
   36 
   37 void
   38 affs_read_inode(struct inode *inode)
   39 {
   40         struct super_block      *sb = inode->i_sb;
   41         struct buffer_head      *bh;
   42         struct affs_head        *head;
   43         struct affs_tail        *tail;
   44         u32                      block;
   45         u32                      size;
   46         u32                      prot;
   47         u16                      id;
   48 
   49         pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
   50 
   51         block = inode->i_ino;
   52         bh = affs_bread(sb, block);
   53         if (!bh) {
   54                 affs_warning(sb, "read_inode", "Cannot read block %d", block);
   55                 goto bad_inode;
   56         }
   57         if (affs_checksum_block(sb, bh) || be32_to_cpu(AFFS_HEAD(bh)->ptype) != T_SHORT) {
   58                 affs_warning(sb,"read_inode",
   59                            "Checksum or type (ptype=%d) error on inode %d",
   60                            AFFS_HEAD(bh)->ptype, block);
   61                 goto bad_inode;
   62         }
   63 
   64         head = AFFS_HEAD(bh);
   65         tail = AFFS_TAIL(sb, bh);
   66         prot = be32_to_cpu(tail->protect);
   67 
   68         inode->i_size = 0;
   69         inode->i_nlink = 1;
   70         inode->i_mode = 0;
   71         memset(AFFS_INODE, 0, sizeof(*AFFS_INODE));
   72         init_MUTEX(&AFFS_INODE->i_link_lock);
   73         init_MUTEX(&AFFS_INODE->i_ext_lock);
   74         AFFS_INODE->i_extcnt = 1;
   75         AFFS_INODE->i_ext_last = ~1;
   76         AFFS_INODE->i_protect = prot;
   77 
   78         if (AFFS_SB->s_flags & SF_SETMODE)
   79                 inode->i_mode = AFFS_SB->s_mode;
   80         else
   81                 inode->i_mode = prot_to_mode(prot);
   82 
   83         id = be16_to_cpu(tail->uid);
   84         if (id == 0 || AFFS_SB->s_flags & SF_SETUID)
   85                 inode->i_uid = AFFS_SB->s_uid;
   86         else if (id == 0xFFFF && AFFS_SB->s_flags & SF_MUFS)
   87                 inode->i_uid = 0;
   88         else
   89                 inode->i_uid = id;
   90 
   91         id = be16_to_cpu(tail->gid);
   92         if (id == 0 || AFFS_SB->s_flags & SF_SETGID)
   93                 inode->i_gid = AFFS_SB->s_gid;
   94         else if (id == 0xFFFF && AFFS_SB->s_flags & SF_MUFS)
   95                 inode->i_gid = 0;
   96         else
   97                 inode->i_gid = id;
   98 
   99         switch (be32_to_cpu(tail->stype)) {
  100         case ST_ROOT:
  101                 inode->i_uid = AFFS_SB->s_uid;
  102                 inode->i_gid = AFFS_SB->s_gid;
  103                 /* fall through */
  104         case ST_USERDIR:
  105                 if (be32_to_cpu(tail->stype) == ST_USERDIR ||
  106                     AFFS_SB->s_flags & SF_SETMODE) {
  107                         if (inode->i_mode & S_IRUSR)
  108                                 inode->i_mode |= S_IXUSR;
  109                         if (inode->i_mode & S_IRGRP)
  110                                 inode->i_mode |= S_IXGRP;
  111                         if (inode->i_mode & S_IROTH)
  112                                 inode->i_mode |= S_IXOTH;
  113                         inode->i_mode |= S_IFDIR;
  114                 } else
  115                         inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
  116                 if (tail->link_chain)
  117                         inode->i_nlink = 2;
  118                 /* Maybe it should be controlled by mount parameter? */
  119                 //inode->i_mode |= S_ISVTX;
  120                 inode->i_op = &affs_dir_inode_operations;
  121                 inode->i_fop = &affs_dir_operations;
  122                 break;
  123         case ST_LINKDIR:
  124 #if 0
  125                 affs_warning(sb, "read_inode", "inode is LINKDIR");
  126                 goto bad_inode;
  127 #else
  128                 inode->i_mode |= S_IFDIR;
  129                 inode->i_op = NULL;
  130                 inode->i_fop = NULL;
  131                 break;
  132 #endif
  133         case ST_LINKFILE:
  134                 affs_warning(sb, "read_inode", "inode is LINKFILE");
  135                 goto bad_inode;
  136         case ST_FILE:
  137                 size = be32_to_cpu(tail->size);
  138                 inode->i_mode |= S_IFREG;
  139                 AFFS_INODE->mmu_private = inode->i_size = size;
  140                 if (inode->i_size) {
  141                         AFFS_INODE->i_blkcnt = (size - 1) /
  142                                                AFFS_SB->s_data_blksize + 1;
  143                         AFFS_INODE->i_extcnt = (AFFS_INODE->i_blkcnt - 1) /
  144                                                AFFS_SB->s_hashsize + 1;
  145                 }
  146                 if (tail->link_chain)
  147                         inode->i_nlink = 2;
  148                 inode->i_mapping->a_ops = (AFFS_SB->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
  149                 inode->i_op = &affs_file_inode_operations;
  150                 inode->i_fop = &affs_file_operations;
  151                 break;
  152         case ST_SOFTLINK:
  153                 inode->i_mode |= S_IFLNK;
  154                 inode->i_op = &affs_symlink_inode_operations;
  155                 inode->i_data.a_ops = &affs_symlink_aops;
  156                 break;
  157         }
  158 
  159         inode->i_mtime = inode->i_atime = inode->i_ctime
  160                        = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
  161                          be32_to_cpu(tail->change.mins) * 60 +
  162                          be32_to_cpu(tail->change.ticks) / 50 +
  163                          ((8 * 365 + 2) * 24 * 60 * 60)) +
  164                          sys_tz.tz_minuteswest * 60;
  165         affs_brelse(bh);
  166         return;
  167 
  168 bad_inode:
  169         make_bad_inode(inode);
  170         affs_brelse(bh);
  171         return;
  172 }
  173 
  174 void
  175 affs_write_inode(struct inode *inode, int unused)
  176 {
  177         struct super_block      *sb = inode->i_sb;
  178         struct buffer_head      *bh;
  179         struct affs_tail        *tail;
  180         uid_t                    uid;
  181         gid_t                    gid;
  182 
  183         pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
  184 
  185         if (!inode->i_nlink)
  186                 // possibly free block
  187                 return;
  188         lock_kernel();
  189         bh = affs_bread(sb, inode->i_ino);
  190         if (!bh) {
  191                 affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
  192                 unlock_kernel();
  193                 return;
  194         }
  195         tail = AFFS_TAIL(sb, bh);
  196         if (tail->stype == be32_to_cpu(ST_ROOT)) {
  197                 secs_to_datestamp(inode->i_mtime,&AFFS_ROOT_TAIL(sb, bh)->root_change);
  198         } else {
  199                 tail->protect = cpu_to_be32(AFFS_INODE->i_protect);
  200                 tail->size = cpu_to_be32(inode->i_size);
  201                 secs_to_datestamp(inode->i_mtime,&tail->change);
  202                 if (!(inode->i_ino == AFFS_SB->s_root_block)) {
  203                         uid = inode->i_uid;
  204                         gid = inode->i_gid;
  205                         if (sb->u.affs_sb.s_flags & SF_MUFS) {
  206                                 if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
  207                                         uid = inode->i_uid ^ ~0;
  208                                 if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
  209                                         gid = inode->i_gid ^ ~0;
  210                         }
  211                         if (!(sb->u.affs_sb.s_flags & SF_SETUID))
  212                                 tail->uid = cpu_to_be16(uid);
  213                         if (!(sb->u.affs_sb.s_flags & SF_SETGID))
  214                                 tail->gid = cpu_to_be16(gid);
  215                 }
  216         }
  217         affs_fix_checksum(sb, bh);
  218         mark_buffer_dirty_inode(bh, inode);
  219         affs_brelse(bh);
  220         unlock_kernel();
  221 }
  222 
  223 int
  224 affs_notify_change(struct dentry *dentry, struct iattr *attr)
  225 {
  226         struct inode *inode = dentry->d_inode;
  227         int error;
  228 
  229         pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
  230 
  231         error = inode_change_ok(inode,attr);
  232         if (error)
  233                 goto out;
  234 
  235         if (((attr->ia_valid & ATTR_UID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) ||
  236             ((attr->ia_valid & ATTR_GID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) ||
  237             ((attr->ia_valid & ATTR_MODE) &&
  238              (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE)))) {
  239                 if (!(inode->i_sb->u.affs_sb.s_flags & SF_QUIET))
  240                         error = -EPERM;
  241                 goto out;
  242         }
  243 
  244         inode_setattr(inode, attr);
  245         if (!error && (attr->ia_valid & ATTR_MODE))
  246                 mode_to_prot(inode);
  247 out:
  248         return error;
  249 }
  250 
  251 void
  252 affs_put_inode(struct inode *inode)
  253 {
  254         pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
  255         lock_kernel();
  256         affs_free_prealloc(inode);
  257         if (atomic_read(&inode->i_count) == 1) {
  258                 if (inode->i_size != AFFS_INODE->mmu_private)
  259                         affs_truncate(inode);
  260                 //if (inode->i_nlink)
  261                 //      affs_clear_inode(inode);
  262         }
  263         unlock_kernel();
  264 }
  265 
  266 void
  267 affs_delete_inode(struct inode *inode)
  268 {
  269         pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
  270         lock_kernel();
  271         inode->i_size = 0;
  272         if (S_ISREG(inode->i_mode))
  273                 affs_truncate(inode);
  274         clear_inode(inode);
  275         affs_free_block(inode->i_sb, inode->i_ino);
  276         unlock_kernel();
  277 }
  278 
  279 void
  280 affs_clear_inode(struct inode *inode)
  281 {
  282         unsigned long cache_page = (unsigned long) inode->u.affs_i.i_lc;
  283 
  284         pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
  285         if (cache_page) {
  286                 pr_debug("AFFS: freeing ext cache\n");
  287                 inode->u.affs_i.i_lc = NULL;
  288                 inode->u.affs_i.i_ac = NULL;
  289                 free_page(cache_page);
  290         }
  291         affs_brelse(AFFS_INODE->i_ext_bh);
  292         AFFS_INODE->i_ext_last = ~1;
  293         AFFS_INODE->i_ext_bh = NULL;
  294 }
  295 
  296 struct inode *
  297 affs_new_inode(struct inode *dir)
  298 {
  299         struct super_block      *sb = dir->i_sb;
  300         struct inode            *inode;
  301         u32                      block;
  302         struct buffer_head      *bh;
  303 
  304         if (!(inode = new_inode(sb)))
  305                 goto err_inode;
  306 
  307         if (!(block = affs_alloc_block(dir, dir->i_ino)))
  308                 goto err_block;
  309 
  310         bh = affs_getzeroblk(sb, block);
  311         if (!bh)
  312                 goto err_bh;
  313         mark_buffer_dirty_inode(bh, inode);
  314         affs_brelse(bh);
  315 
  316         inode->i_uid     = current->fsuid;
  317         inode->i_gid     = current->fsgid;
  318         inode->i_ino     = block;
  319         inode->i_nlink   = 1;
  320         inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  321         memset(AFFS_INODE, 0, sizeof(*AFFS_INODE));
  322         AFFS_INODE->i_extcnt = 1;
  323         AFFS_INODE->i_ext_last = ~1;
  324         init_MUTEX(&AFFS_INODE->i_link_lock);
  325         init_MUTEX(&AFFS_INODE->i_ext_lock);
  326 
  327         insert_inode_hash(inode);
  328 
  329         return inode;
  330 
  331 err_bh:
  332         affs_free_block(sb, block);
  333 err_block:
  334         iput(inode);
  335 err_inode:
  336         return NULL;
  337 }
  338 
  339 /*
  340  * Add an entry to a directory. Create the header block
  341  * and insert it into the hash table.
  342  */
  343 
  344 int
  345 affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
  346 {
  347         struct super_block *sb = dir->i_sb;
  348         struct buffer_head *inode_bh = NULL;
  349         struct buffer_head *bh = NULL;
  350         u32 block = 0;
  351         int retval;
  352 
  353         pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)\n", (u32)dir->i_ino,
  354                  (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);
  355 
  356         retval = -EIO;
  357         bh = affs_bread(sb, inode->i_ino);
  358         if (!bh)
  359                 goto done;
  360 
  361         affs_lock_link(inode);
  362         switch (type) {
  363         case ST_LINKFILE:
  364         case ST_LINKDIR:
  365                 inode_bh = bh;
  366                 retval = -ENOSPC;
  367                 block = affs_alloc_block(dir, dir->i_ino);
  368                 if (!block)
  369                         goto err;
  370                 retval = -EIO;
  371                 bh = affs_getzeroblk(sb, block);
  372                 if (!bh)
  373                         goto err;
  374                 break;
  375         default:
  376                 break;
  377         }
  378 
  379         AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
  380         AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
  381         affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
  382         AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
  383         AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
  384 
  385         if (inode_bh) {
  386                 u32 chain;
  387                 chain = AFFS_TAIL(sb, inode_bh)->link_chain;
  388                 AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
  389                 AFFS_TAIL(sb, bh)->link_chain = chain;
  390                 AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
  391                 affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
  392                 mark_buffer_dirty_inode(inode_bh, inode);
  393                 inode->i_nlink = 2;
  394                 atomic_inc(&inode->i_count);
  395         }
  396         affs_fix_checksum(sb, bh);
  397         mark_buffer_dirty_inode(bh, inode);
  398         dentry->d_fsdata = (void *)bh->b_blocknr;
  399 
  400         affs_lock_dir(dir);
  401         retval = affs_insert_hash(dir, bh);
  402         mark_buffer_dirty_inode(bh, inode);
  403         affs_unlock_dir(dir);
  404         affs_unlock_link(inode);
  405 
  406         d_instantiate(dentry, inode);
  407 done:
  408         affs_brelse(inode_bh);
  409         affs_brelse(bh);
  410         return retval;
  411 err:
  412         if (block)
  413                 affs_free_block(sb, block);
  414         affs_unlock_link(inode);
  415         goto done;
  416 }
  417 MODULE_LICENSE("GPL");

Cache object: a3ad1ce26c4e8fcfc63816bcfc58b7fd


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.