• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

inode.c

Go to the documentation of this file.
00001 
00012 #include <linux/module.h>
00013 #include <linux/fs.h>
00014 #include <linux/pagemap.h>
00015 #include <linux/highmem.h>
00016 #include <linux/init.h>
00017 #include <linux/string.h>
00018 #include <linux/smp_lock.h>
00019 #include <linux/backing-dev.h>
00020 #include <linux/slab.h>
00021 #include <linux/statfs.h>
00022 #include <asm/uaccess.h>
00023 
00024 #include "mountdata.h"
00025 #include "procfs.h"
00026 #include "storage.h"
00027 #include "file.h"
00028 
00029 
00030 
00031 #define MUMUFS_MAGIC    0x710110
00032 
00033 
00034 MODULE_LICENSE( "GPL" );
00035 MODULE_AUTHOR( "Sergey Satskiy" );
00036 MODULE_DESCRIPTION( "MuMu filesystem supports multiple writers and multiple readers" );
00037 
00038 
00039 
00043 struct kmem_cache *     mumufs_storage_cache;
00044 
00045 
00046 static struct super_operations              mumufs_ops;
00047 static struct address_space_operations      mumufs_aops;
00048 static struct inode_operations              mumufs_file_inode_operations;
00049 static struct inode_operations              mumufs_dir_inode_operations;
00050 static struct file_operations               mumufs_file_operations;
00051 static struct backing_dev_info              mumufs_backing_dev_info;
00052 
00053 
00057 static struct backing_dev_info              mumufs_backing_dev_info =
00058 {
00059     .ra_pages       = 0,                                                /* No readahead */
00060     .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
00061                       /*
00062                       BDI_CAP_MAP_DIRECT    | BDI_CAP_MAP_COPY |
00063                       BDI_CAP_READ_MAP      | BDI_CAP_WRITE_MAP,
00064                       */
00065 };
00066 
00067 
00068 
00076 static struct inode *  mumufs_get_inode( struct super_block *  sb,
00077                                          int                   mode,
00078                                          dev_t                 dev )
00079 {
00080     if ( S_ISREG( mode ) || S_ISDIR( mode ) || S_ISLNK( mode ) )
00081     {
00082         struct inode *      inode = NULL;
00083 
00084         /* Check the mode - it cannot be executable for a regular file */
00085         if ( S_ISREG( mode ) && (mode & S_IXUGO) ) return NULL;
00086 
00087         inode = new_inode( sb );
00088         if ( inode != NULL )
00089         {
00090             inode->i_mode = mode;
00091             inode->i_uid = current_fsuid();
00092             inode->i_gid = current_fsgid();
00093             inode->i_blocks = 0;
00094             inode->i_mapping->a_ops = &mumufs_aops;
00095             inode->i_mapping->backing_dev_info = &mumufs_backing_dev_info;
00096             inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
00097             inode->i_private = NULL;
00098 
00099             switch ( mode & S_IFMT )
00100             {
00101                 case S_IFREG:
00102 
00103                     {
00104                         int     records = atomic_read( & ((struct mumu_mount_data *)(sb->s_fs_info))->number_of_entries );
00105                         if ( records >= ((struct mumu_mount_data *)(sb->s_fs_info))->max_entries )
00106                         {
00107                             iput( inode );
00108                             return NULL;
00109                         }
00110                     }
00111 
00112                     inode->i_op = & mumufs_file_inode_operations;
00113                     inode->i_fop = & mumufs_file_operations;
00114 
00115                         /* Alloc the node storage */
00116                     inode->i_private = mumufs_allocate_storage();
00117                     if ( inode->i_private == NULL )
00118                     {
00119                         iput( inode );
00120                         return NULL;
00121                     }
00122 
00123                         /* Increment # of entries */
00124                     atomic_inc( & ((struct mumu_mount_data *)(sb->s_fs_info))->number_of_entries );
00125                     break;
00126                 case S_IFDIR:
00127                     inode->i_op = & mumufs_dir_inode_operations;
00128                     inode->i_fop = & simple_dir_operations;
00129                         /* directory inodes start off with i_nlink == 2 (for "." entry) */
00130                     inode->i_nlink++;
00131                     break;
00132                 case S_IFLNK:
00133                     inode->i_op = & page_symlink_inode_operations;
00134                     break;
00135                 default:
00136                         /* It is impossible - we have 'if' at the beginning */
00137                     break;
00138             }
00139         }
00140         return inode;
00141     }
00142 
00143     return NULL;
00144 }
00145 
00146 
00154 static int mumufs_inode_unlink( struct inode *      dir,
00155                                 struct dentry *     dentry )
00156 {
00157     if ( (dentry->d_inode->i_private != NULL) &&
00158          ((dentry->d_inode->i_mode & S_IFMT) == S_IFREG) )
00159     {
00160             /* It was a regular file. We need to del all the related data:  */
00161             /* data buffer and the node itself from the list of SB nodes    */
00162         mumufs_free_storage( (struct mumufs_storage *)( dentry->d_inode->i_private ) );
00163         dentry->d_inode->i_private = NULL;
00164 
00165             /* Decrement # of entries               */
00166         atomic_dec( & ((struct mumu_mount_data *)(dir->i_sb->s_fs_info))->number_of_entries );
00167     }
00168 
00169         /* TODO: Do I need the following?   */
00170         /* d_invalidate( dentry );          */
00171         /* iput( dentry->d_inode );         */
00172     return simple_unlink( dir, dentry );
00173 }
00174 
00175 
00176 
00177 
00186 static int  mumufs_mknod( struct inode *     dir,
00187                           struct dentry *    dentry,
00188                           int                mode,
00189                           dev_t              dev )
00190 {
00191     struct inode *      inode = mumufs_get_inode( dir->i_sb, mode, dev );
00192 
00193     if ( inode != NULL )
00194     {
00195         if ( dir->i_mode & S_ISGID )
00196         {
00197             inode->i_gid = dir->i_gid;
00198             if ( S_ISDIR( mode ) )
00199             {
00200                 inode->i_mode |= S_ISGID;
00201             }
00202         }
00203         d_instantiate( dentry, inode );
00204         dget( dentry );        /* Extra count - pin the dentry in core */
00205         return 0;
00206     }
00207     return -ENOSPC;
00208 }
00209 
00210 
00211 
00212 
00220 static int mumufs_mkdir( struct inode *     dir,
00221                          struct dentry *    dentry,
00222                          int                mode )
00223 {
00224     int         retval = mumufs_mknod( dir, dentry, mode | S_IFDIR, 0 );
00225 
00226     if ( !retval )
00227     {
00228         dir->i_nlink++;
00229     }
00230     return retval;
00231 }
00232 
00233 
00234 
00235 
00243 static int mumufs_create( struct inode *        dir,
00244                           struct dentry *       dentry,
00245                           int                   mode,
00246                           struct nameidata *    nd )
00247 {
00248     return mumufs_mknod( dir, dentry, mode | S_IFREG, 0 );
00249 }
00250 
00251 
00252 
00253 
00261 static int mumufs_symlink( struct inode *   dir,
00262                            struct dentry *  dentry,
00263                            const char *     symname )
00264 {
00265     struct inode *      inode = NULL;
00266     int                 error = -ENOSPC;
00267 
00268     inode = mumufs_get_inode( dir->i_sb, S_IFLNK | S_IRWXUGO, 0 );
00269     if ( inode != NULL )
00270     {
00271         error = page_symlink( inode, symname, strlen( symname ) + 1 );
00272         if ( !error )
00273         {
00274             if ( dir->i_mode & S_ISGID )
00275             {
00276                 inode->i_gid = dir->i_gid;
00277             }
00278             d_instantiate( dentry, inode );
00279             dget( dentry );
00280         }
00281         else
00282         {
00283             iput( inode );
00284         }
00285     }
00286 
00287     return error;
00288 }
00289 
00290 
00297 static int  mumufs_inode_setattr( struct dentry *  dentry,
00298                                   struct iattr *   iattr)
00299 {
00300     struct inode *      inode = dentry->d_inode;
00301     int                 ret;
00302 
00303     ret = inode_change_ok( inode, iattr );
00304     if ( ret != 0 )
00305     {
00306         return ret;
00307     }
00308 
00309     /* Forbid to make regular file executable                     */
00310     /* No need to check for file type because this function is    */
00311     /* used for regular inodes only                               */
00312     if ( iattr->ia_valid & ATTR_MODE )
00313     {
00314         if ( iattr->ia_mode & S_IXUGO ) return -EINVAL;
00315     }
00316 
00317     return inode_setattr( inode, iattr );
00318 }
00319 
00320 
00328 static loff_t  mumufs_no_llseek( struct file *  file,
00329                                  loff_t         offset,
00330                                  int            origin )
00331 {
00332     /* seek operation is illegal for mumufs.                                 */
00333     /* There is ESPIPE return code which is used for illegal seek operations */
00334     /* for pipes however mumufs is not a pipe so it returns EINVAL           */
00335     return -EINVAL;
00336 }
00337 
00338 
00339     /* Links will not work without this  */
00340 static struct address_space_operations      mumufs_aops =
00341 {
00342     .readpage       = simple_readpage,
00343     .write_begin    = simple_write_begin,
00344     .write_end      = simple_write_end,
00345 };
00346 
00347 
00348 
00349 static struct file_operations               mumufs_file_operations =
00350 {
00351     .open       = mumufs_file_open,
00352     .read       = mumufs_file_read,
00353     .write      = mumufs_file_write,
00354     .release    = mumufs_file_release,
00355     .llseek     = mumufs_no_llseek,
00356 
00357     .poll       = mumufs_file_poll,     /* select & poll support */
00358 };
00359 
00360 
00361 
00362 static struct inode_operations              mumufs_file_inode_operations =
00363 {
00364     .getattr    = simple_getattr,
00365     .setattr    = mumufs_inode_setattr,
00366 };
00367 
00368 
00369 
00370 static struct inode_operations              mumufs_dir_inode_operations =
00371 {
00372     .create     = mumufs_create,
00373     .lookup     = simple_lookup,
00374     .link       = simple_link,
00375     .unlink     = mumufs_inode_unlink,
00376     .symlink    = mumufs_symlink,
00377     .mkdir      = mumufs_mkdir,
00378     .rmdir      = simple_rmdir,
00379     .mknod      = mumufs_mknod,
00380     .rename     = simple_rename,
00381 };
00382 
00383 
00388 static void mumufs_put_super( struct super_block *  sb )
00389 {
00390     mumufs_remove_mount_info( sb );     /* /proc/ entry removal           */
00391     mumufs_umount_cleanup( sb );
00392     kfree( sb->s_fs_info );             /* mumu_mount_data removal        */
00393 
00394     /* TODO: Do I need to shrink this stuff?    */
00395     /*    shrink_dcache_sb( sb );               */
00396     /*    invalidate_inodes( sb );              */
00397 }
00398 
00399 
00414 static int mumufs_statfs( struct dentry *  dentry, struct kstatfs *  buf )
00415 {
00416     struct super_block *        sb = dentry->d_sb;
00417     struct mumu_mount_data *    d = (struct mumu_mount_data *)( sb->s_fs_info );
00418 
00419     buf->f_type = MUMUFS_MAGIC;
00420     buf->f_bsize = 1;
00421     buf->f_blocks = d->max_entries;
00422     buf->f_bfree = d->max_entries - d->number_of_entries.counter;
00423     buf->f_bavail = buf->f_bfree;
00424     buf->f_files = buf->f_blocks;
00425     buf->f_ffree = buf->f_bfree;
00426     buf->f_namelen = NAME_MAX;
00427     buf->f_frsize = 1;
00428 
00429     return 0;
00430 }
00431 
00432 static struct super_operations              mumufs_ops =
00433 {
00434     .statfs         = mumufs_statfs,
00435     .drop_inode     = generic_delete_inode,
00436     .put_super      = mumufs_put_super,
00437     .show_options   = mumufs_show_options,
00438 };
00439 
00440 
00441 
00449 static int mumufs_fill_super( struct super_block *      sb,
00450                               void *                    data,
00451                               int                       silent )
00452 {
00453     struct inode *              inode;
00454     struct dentry *             root;
00455     struct mumu_mount_data *    mount_data;
00456 
00457 
00458     mount_data = kmalloc( sizeof( struct mumu_mount_data ), GFP_KERNEL );
00459     if ( mount_data == NULL )
00460     {
00461         return -ENOMEM;
00462     }
00463 
00464     memset( mount_data, 0, sizeof( struct mumu_mount_data ) );
00465     if ( mumufs_init_mount_data( mount_data ) != 0 )
00466     {
00467         kfree( mount_data );
00468         return -ENOMEM;
00469     }
00470 
00471     if ( !mumufs_parse_opt( (char *)data, mount_data ) )
00472     {
00473         kfree( mount_data );
00474         return -EINVAL;
00475     }
00476 
00477     sb->s_maxbytes = MAX_LFS_FILESIZE;
00478     sb->s_blocksize = 1;
00479     sb->s_magic = MUMUFS_MAGIC;
00480     sb->s_op = &mumufs_ops;
00481     sb->s_time_gran = 1;
00482     sb->s_fs_info = mount_data;
00483 
00484     inode = mumufs_get_inode( sb, S_IFDIR | 0755, 0 );
00485     if ( !inode )
00486     {
00487         kfree( mount_data );
00488         return -ENOMEM;
00489     }
00490 
00491     root = d_alloc_root( inode );
00492     if ( !root )
00493     {
00494         kfree( mount_data );
00495         iput( inode );
00496         return -ENOMEM;
00497     }
00498     sb->s_root = root;
00499 
00500         /* It is the point when a file system is mounted */
00501     {
00502         int     ret = mumufs_create_mount_info( sb );
00503         if ( ret != 0 )
00504         {
00505             kfree( mount_data );
00506             iput( inode );
00507             dput( root );
00508             return ret;
00509         }
00510     }
00511 
00512     return 0;
00513 }
00514 
00515 
00516 
00526 int  mumufs_get_sb( struct file_system_type *      fs_type,
00527                     int                            flags,
00528                     const char *                   dev_name,
00529                     void *                         data,
00530                     struct vfsmount *              mnt )
00531 {
00532     int     ret;
00533 
00534     ret = get_sb_nodev( fs_type, flags, data, mumufs_fill_super, mnt );
00535     if ( ret == 0 )
00536     {
00537         struct super_block *        sb = mnt->mnt_sb;
00538 
00539         /* Memorize vfsmount pointer. It is required to display the mount */
00540         /* point in the /proc/mumufs/...                                  */
00541         ((struct mumu_mount_data *)(sb->s_fs_info))->mount = mnt;
00542     }
00543     return ret;
00544 }
00545 
00546 
00551 void  mumufs_kill_super( struct super_block *  sb )
00552 {
00553     struct inode *      inode;
00554     struct inode *      next_i;
00555 
00556         /* Iterate over the fs inodes */
00557     list_for_each_entry_safe(inode, next_i, & sb->s_inodes, i_sb_list)
00558     {
00559         if ( inode->i_mode && S_IFREG )
00560         {
00561             if ( inode->i_private != NULL )
00562             {
00563                 mumufs_free_storage( (struct mumufs_storage *)( inode->i_private ) );
00564             }
00565         }
00566     }
00567 
00568     return kill_litter_super( sb );
00569 }
00570 
00571 
00572 static struct file_system_type      mumufs_fs_type =
00573 {
00574     .owner      = THIS_MODULE,
00575     .name       = "mumufs",
00576     .get_sb     = mumufs_get_sb,
00577     .kill_sb    = mumufs_kill_super,
00578 };
00579 
00580 
00581 
00586 static int __init init_mumufs_fs( void )
00587 {
00588     int         ret;
00589 
00590     mumufs_storage_cache = kmem_cache_create( "mumu_storage", sizeof( struct mumufs_storage ),
00591                                               0, SLAB_HWCACHE_ALIGN, NULL );
00592     if ( mumufs_storage_cache == NULL )
00593     {
00594         return -EFAULT;
00595     }
00596 
00597     if ( mumufs_initialise_proc_entries() != 0 )
00598     {
00599         kmem_cache_destroy( mumufs_storage_cache );
00600         return -EFAULT;
00601     }
00602 
00603     ret = register_filesystem( &mumufs_fs_type );
00604     if ( ret != 0 )
00605     {
00606         kmem_cache_destroy( mumufs_storage_cache );
00607         mumufs_remove_proc_entries();
00608     }
00609 
00610     return ret;
00611 }
00612 
00613 
00621 static void __exit exit_mumufs_fs( void )
00622 {
00623     mumufs_remove_proc_entries();
00624     unregister_filesystem( &mumufs_fs_type );
00625     kmem_cache_destroy( mumufs_storage_cache );
00626     return;
00627 }
00628 
00629 
00630 module_init( init_mumufs_fs )
00631 module_exit( exit_mumufs_fs )
00632 
00633