root/fs/inode.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. inode_init
  2. wait_on_inode
  3. lock_inode
  4. unlock_inode
  5. clear_inode
  6. fs_may_mount
  7. fs_may_umount
  8. write_inode
  9. read_inode
  10. notify_change
  11. bmap
  12. invalidate_inodes
  13. sync_inodes
  14. iput
  15. get_empty_inode
  16. get_pipe_inode
  17. iget
  18. __wait_on_inode

   1 /*
   2  *  linux/fs/inode.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/stat.h>
   8 #include <linux/sched.h>
   9 #include <linux/kernel.h>
  10 #include <linux/mm.h>
  11 #include <linux/string.h>
  12 
  13 #include <asm/system.h>
  14 
  15 static struct inode * inode_table;
  16 static struct inode * last_inode;
  17 static struct wait_queue * inode_wait = NULL;
  18 
  19 unsigned long inode_init(unsigned long start, unsigned long end)
     /* [previous][next][first][last][top][bottom][index][help] */
  20 {
  21         start += 0x0000000f;
  22         start &= 0xfffffff0;
  23         inode_table = (struct inode *) start;
  24         last_inode = inode_table;
  25         start = (unsigned long) (inode_table + NR_INODE);
  26         memset(inode_table,0,NR_INODE*sizeof(struct inode));
  27         return start;
  28 }
  29 
  30 static void __wait_on_inode(struct inode *);
  31 
  32 static inline void wait_on_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  33 {
  34         if (inode->i_lock)
  35                 __wait_on_inode(inode);
  36 }
  37 
  38 static inline void lock_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40         wait_on_inode(inode);
  41         inode->i_lock = 1;
  42 }
  43 
  44 static inline void unlock_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46         inode->i_lock = 0;
  47         wake_up(&inode->i_wait);
  48 }
  49 
  50 /*
  51  * Note that we don't want to disturb any wait-queues when we discard
  52  * an inode.
  53  *
  54  * Argghh. Got bitten by a gcc problem with inlining: no way to tell
  55  * the compiler that the inline asm function 'memset' changes 'inode'.
  56  * I've been searching for the bug for days, and was getting desperate.
  57  * Finally looked at the assembler output... Grrr.
  58  *
  59  * The solution is the weird use of 'volatile'. Ho humm. Have to report
  60  * it to the gcc lists, and hope we can do this more cleanly some day..
  61  */
  62 void clear_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64         struct wait_queue * wait;
  65 
  66         wait_on_inode(inode);
  67         wait = ((volatile struct inode *) inode)->i_wait;
  68         memset(inode,0,sizeof(*inode));
  69         ((volatile struct inode *) inode)->i_wait = wait;
  70 }
  71 
  72 int fs_may_mount(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         struct inode * inode;
  75 
  76         for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
  77                 if (inode->i_dev != dev)
  78                         continue;
  79                 if (inode->i_count || inode->i_dirt || inode->i_lock)
  80                         return 0;
  81                 clear_inode(inode);
  82         }
  83         return 1;
  84 }
  85 
  86 int fs_may_umount(dev_t dev, struct inode * mount_root)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         struct inode * inode;
  89 
  90         for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
  91                 if (inode->i_dev==dev && inode->i_count)
  92                         if (inode == mount_root && inode->i_count == 1)
  93                                 continue;
  94                         else
  95                                 return 0;
  96         }
  97         return 1;
  98 }
  99 
 100 static void write_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102         if (!inode->i_dirt)
 103                 return;
 104         wait_on_inode(inode);
 105         if (!inode->i_dirt)
 106                 return;
 107         if (!inode->i_sb || !inode->i_sb->s_op || !inode->i_sb->s_op->write_inode) {
 108                 inode->i_dirt = 0;
 109                 return;
 110         }
 111         inode->i_lock = 1;      
 112         inode->i_sb->s_op->write_inode(inode);
 113         unlock_inode(inode);
 114 }
 115 
 116 static void read_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118         lock_inode(inode);
 119         if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->read_inode)
 120                 inode->i_sb->s_op->read_inode(inode);
 121         unlock_inode(inode);
 122 }
 123 
 124 /*
 125  * notify_change is called for inode-changing operations such as
 126  * chown, chmod, utime, and truncate.  It is guaranteed (unlike
 127  * write_inode) to be called from the context of the user requesting
 128  * the change.  It is not called for ordinary access-time updates.
 129  * NFS uses this to get the authentication correct.  -- jrs
 130  */
 131 
 132 int notify_change(int flags, struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134         if (inode->i_sb && inode->i_sb->s_op  &&
 135             inode->i_sb->s_op->notify_change)
 136                 return inode->i_sb->s_op->notify_change(flags, inode);
 137         return 0;
 138 }
 139 
 140 /*
 141  * bmap is needed for demand-loading and paging: if this function
 142  * doesn't exist for a filesystem, then those things are impossible:
 143  * executables cannot be run from the filesystem etc...
 144  *
 145  * This isn't as bad as it sounds: the read-routines might still work,
 146  * so the filesystem would be otherwise ok (for example, you might have
 147  * a DOS filesystem, which doesn't lend itself to bmap very well, but
 148  * you could still transfer files to/from the filesystem)
 149  */
 150 int bmap(struct inode * inode, int block)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         if (inode->i_op && inode->i_op->bmap)
 153                 return inode->i_op->bmap(inode,block);
 154         return 0;
 155 }
 156 
 157 void invalidate_inodes(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159         int i;
 160         struct inode * inode;
 161 
 162         inode = 0+inode_table;
 163         for(i=0 ; i<NR_INODE ; i++,inode++) {
 164                 wait_on_inode(inode);
 165                 if (inode->i_dev == dev) {
 166                         if (inode->i_count) {
 167                                 printk("inode in use on removed disk\n\r");
 168                                 continue;
 169                         }
 170                         clear_inode(inode);
 171                 }
 172         }
 173 }
 174 
 175 void sync_inodes(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177         struct inode * inode;
 178 
 179         for(inode = 0+inode_table ; inode < NR_INODE+inode_table ; inode++) {
 180                 if (dev && inode->i_dev != dev)
 181                         continue;
 182                 wait_on_inode(inode);
 183                 if (inode->i_dirt)
 184                         write_inode(inode);
 185         }
 186 }
 187 
 188 void iput(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         if (!inode)
 191                 return;
 192         wait_on_inode(inode);
 193         if (!inode->i_count) {
 194                 printk("iput: trying to free free inode\n");
 195                 printk("device %04x, inode %d, mode=%07o\n",inode->i_rdev,
 196                         inode->i_ino,inode->i_mode);
 197                 return;
 198         }
 199         if (inode->i_pipe) {
 200                 wake_up(&PIPE_READ_WAIT(*inode));
 201                 wake_up(&PIPE_WRITE_WAIT(*inode));
 202         }
 203 repeat:
 204         if (inode->i_count>1) {
 205                 inode->i_count--;
 206                 return;
 207         }
 208         wake_up(&inode_wait);
 209         if (inode->i_pipe) {
 210                 unsigned long page = (unsigned long) PIPE_BASE(*inode);
 211                 PIPE_BASE(*inode) = NULL;
 212                 free_page(page);
 213         }
 214         if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
 215                 inode->i_sb->s_op->put_inode(inode);
 216                 if (!inode->i_nlink)
 217                         return;
 218         }
 219         if (inode->i_dirt) {
 220                 write_inode(inode);     /* we can sleep - so do again */
 221                 wait_on_inode(inode);
 222                 goto repeat;
 223         }
 224         inode->i_count--;
 225         return;
 226 }
 227 
 228 struct inode * get_empty_inode(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230         struct inode * inode;
 231         int i;
 232 
 233 repeat:
 234         inode = NULL;
 235         for (i = NR_INODE; i ; i--) {
 236                 if (++last_inode >= inode_table + NR_INODE)
 237                         last_inode = inode_table;
 238                 if (!last_inode->i_count) {
 239                         inode = last_inode;
 240                         if (!inode->i_dirt && !inode->i_lock)
 241                                 break;
 242                 }
 243         }
 244         if (!inode) {
 245                 printk("No free inodes - contact Linus\n");
 246                 sleep_on(&inode_wait);
 247                 goto repeat;
 248         }
 249         if (inode->i_lock) {
 250                 wait_on_inode(inode);
 251                 goto repeat;
 252         }
 253         if (inode->i_dirt) {
 254                 write_inode(inode);
 255                 goto repeat;
 256         }
 257         if (inode->i_count)
 258                 goto repeat;
 259         clear_inode(inode);
 260         inode->i_count = 1;
 261         inode->i_nlink = 1;
 262         return inode;
 263 }
 264 
 265 struct inode * get_pipe_inode(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267         struct inode * inode;
 268 
 269         if (!(inode = get_empty_inode()))
 270                 return NULL;
 271         if (!(PIPE_BASE(*inode) = (char *) get_free_page(GFP_USER))) {
 272                 inode->i_count = 0;
 273                 return NULL;
 274         }
 275         inode->i_count = 2;     /* sum of readers/writers */
 276         PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
 277         PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
 278         PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
 279         inode->i_pipe = 1;
 280         return inode;
 281 }
 282 
 283 struct inode * iget(struct super_block * sb,int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285         struct inode * inode, * empty;
 286 
 287         if (!sb)
 288                 panic("iget with sb==NULL");
 289         empty = get_empty_inode();
 290         inode = inode_table;
 291         while (inode < NR_INODE+inode_table) {
 292                 if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
 293                         inode++;
 294                         continue;
 295                 }
 296                 wait_on_inode(inode);
 297                 if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
 298                         inode = inode_table;
 299                         continue;
 300                 }
 301                 inode->i_count++;
 302                 if (inode->i_mount) {
 303                         int i;
 304 
 305                         for (i = 0 ; i<NR_SUPER ; i++)
 306                                 if (super_block[i].s_covered==inode)
 307                                         break;
 308                         if (i >= NR_SUPER) {
 309                                 printk("Mounted inode hasn't got sb\n");
 310                                 if (empty)
 311                                         iput(empty);
 312                                 return inode;
 313                         }
 314                         iput(inode);
 315                         if (!(inode = super_block[i].s_mounted))
 316                                 printk("iget: mounted dev has no rootinode\n");
 317                         else {
 318                                 inode->i_count++;
 319                                 wait_on_inode(inode);
 320                         }
 321                 }
 322                 if (empty)
 323                         iput(empty);
 324                 return inode;
 325         }
 326         if (!empty)
 327                 return (NULL);
 328         inode = empty;
 329         inode->i_sb = sb;
 330         inode->i_dev = sb->s_dev;
 331         inode->i_ino = nr;
 332         inode->i_flags = sb->s_flags;
 333         read_inode(inode);
 334         return inode;
 335 }
 336 
 337 /*
 338  * The "new" scheduling primitives (new as of 0.97 or so) allow this to
 339  * be done without disabling interrupts (other than in the actual queue
 340  * updating things: only a couple of 386 instructions). This should be
 341  * much better for interrupt latency.
 342  */
 343 static void __wait_on_inode(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 344 {
 345         struct wait_queue wait = { current, NULL };
 346 
 347         add_wait_queue(&inode->i_wait, &wait);
 348 repeat:
 349         current->state = TASK_UNINTERRUPTIBLE;
 350         if (inode->i_lock) {
 351                 schedule();
 352                 goto repeat;
 353         }
 354         remove_wait_queue(&inode->i_wait, &wait);
 355         current->state = TASK_RUNNING;
 356 }

/* [previous][next][first][last][top][bottom][index][help] */