cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

inode.c (9723B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  linux/fs/adfs/inode.c
      4 *
      5 *  Copyright (C) 1997-1999 Russell King
      6 */
      7#include <linux/buffer_head.h>
      8#include <linux/writeback.h>
      9#include "adfs.h"
     10
     11/*
     12 * Lookup/Create a block at offset 'block' into 'inode'.  We currently do
     13 * not support creation of new blocks, so we return -EIO for this case.
     14 */
     15static int
     16adfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh,
     17	       int create)
     18{
     19	if (!create) {
     20		if (block >= inode->i_blocks)
     21			goto abort_toobig;
     22
     23		block = __adfs_block_map(inode->i_sb, ADFS_I(inode)->indaddr,
     24					 block);
     25		if (block)
     26			map_bh(bh, inode->i_sb, block);
     27		return 0;
     28	}
     29	/* don't support allocation of blocks yet */
     30	return -EIO;
     31
     32abort_toobig:
     33	return 0;
     34}
     35
     36static int adfs_writepage(struct page *page, struct writeback_control *wbc)
     37{
     38	return block_write_full_page(page, adfs_get_block, wbc);
     39}
     40
     41static int adfs_read_folio(struct file *file, struct folio *folio)
     42{
     43	return block_read_full_folio(folio, adfs_get_block);
     44}
     45
     46static void adfs_write_failed(struct address_space *mapping, loff_t to)
     47{
     48	struct inode *inode = mapping->host;
     49
     50	if (to > inode->i_size)
     51		truncate_pagecache(inode, inode->i_size);
     52}
     53
     54static int adfs_write_begin(struct file *file, struct address_space *mapping,
     55			loff_t pos, unsigned len,
     56			struct page **pagep, void **fsdata)
     57{
     58	int ret;
     59
     60	*pagep = NULL;
     61	ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
     62				adfs_get_block,
     63				&ADFS_I(mapping->host)->mmu_private);
     64	if (unlikely(ret))
     65		adfs_write_failed(mapping, pos + len);
     66
     67	return ret;
     68}
     69
     70static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
     71{
     72	return generic_block_bmap(mapping, block, adfs_get_block);
     73}
     74
     75static const struct address_space_operations adfs_aops = {
     76	.dirty_folio	= block_dirty_folio,
     77	.invalidate_folio = block_invalidate_folio,
     78	.read_folio	= adfs_read_folio,
     79	.writepage	= adfs_writepage,
     80	.write_begin	= adfs_write_begin,
     81	.write_end	= generic_write_end,
     82	.bmap		= _adfs_bmap
     83};
     84
     85/*
     86 * Convert ADFS attributes and filetype to Linux permission.
     87 */
     88static umode_t
     89adfs_atts2mode(struct super_block *sb, struct inode *inode)
     90{
     91	unsigned int attr = ADFS_I(inode)->attr;
     92	umode_t mode, rmask;
     93	struct adfs_sb_info *asb = ADFS_SB(sb);
     94
     95	if (attr & ADFS_NDA_DIRECTORY) {
     96		mode = S_IRUGO & asb->s_owner_mask;
     97		return S_IFDIR | S_IXUGO | mode;
     98	}
     99
    100	switch (adfs_filetype(ADFS_I(inode)->loadaddr)) {
    101	case 0xfc0:	/* LinkFS */
    102		return S_IFLNK|S_IRWXUGO;
    103
    104	case 0xfe6:	/* UnixExec */
    105		rmask = S_IRUGO | S_IXUGO;
    106		break;
    107
    108	default:
    109		rmask = S_IRUGO;
    110	}
    111
    112	mode = S_IFREG;
    113
    114	if (attr & ADFS_NDA_OWNER_READ)
    115		mode |= rmask & asb->s_owner_mask;
    116
    117	if (attr & ADFS_NDA_OWNER_WRITE)
    118		mode |= S_IWUGO & asb->s_owner_mask;
    119
    120	if (attr & ADFS_NDA_PUBLIC_READ)
    121		mode |= rmask & asb->s_other_mask;
    122
    123	if (attr & ADFS_NDA_PUBLIC_WRITE)
    124		mode |= S_IWUGO & asb->s_other_mask;
    125	return mode;
    126}
    127
    128/*
    129 * Convert Linux permission to ADFS attribute.  We try to do the reverse
    130 * of atts2mode, but there is not a 1:1 translation.
    131 */
    132static int adfs_mode2atts(struct super_block *sb, struct inode *inode,
    133			  umode_t ia_mode)
    134{
    135	struct adfs_sb_info *asb = ADFS_SB(sb);
    136	umode_t mode;
    137	int attr;
    138
    139	/* FIXME: should we be able to alter a link? */
    140	if (S_ISLNK(inode->i_mode))
    141		return ADFS_I(inode)->attr;
    142
    143	/* Directories do not have read/write permissions on the media */
    144	if (S_ISDIR(inode->i_mode))
    145		return ADFS_NDA_DIRECTORY;
    146
    147	attr = 0;
    148	mode = ia_mode & asb->s_owner_mask;
    149	if (mode & S_IRUGO)
    150		attr |= ADFS_NDA_OWNER_READ;
    151	if (mode & S_IWUGO)
    152		attr |= ADFS_NDA_OWNER_WRITE;
    153
    154	mode = ia_mode & asb->s_other_mask;
    155	mode &= ~asb->s_owner_mask;
    156	if (mode & S_IRUGO)
    157		attr |= ADFS_NDA_PUBLIC_READ;
    158	if (mode & S_IWUGO)
    159		attr |= ADFS_NDA_PUBLIC_WRITE;
    160
    161	return attr;
    162}
    163
    164static const s64 nsec_unix_epoch_diff_risc_os_epoch = 2208988800000000000LL;
    165
    166/*
    167 * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
    168 * referenced to 1 Jan 1900 (til 2248) so we need to discard 2208988800 seconds
    169 * of time to convert from RISC OS epoch to Unix epoch.
    170 */
    171static void
    172adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
    173{
    174	unsigned int high, low;
    175	/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
    176	 * 01 Jan 1900 00:00:00 (RISC OS epoch)
    177	 */
    178	s64 nsec;
    179
    180	if (!adfs_inode_is_stamped(inode))
    181		goto cur_time;
    182
    183	high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
    184	low  = ADFS_I(inode)->execaddr;    /* bottom 32 bits of timestamp */
    185
    186	/* convert 40-bit centi-seconds to 32-bit seconds
    187	 * going via nanoseconds to retain precision
    188	 */
    189	nsec = (((s64) high << 32) | (s64) low) * 10000000; /* cs to ns */
    190
    191	/* Files dated pre  01 Jan 1970 00:00:00. */
    192	if (nsec < nsec_unix_epoch_diff_risc_os_epoch)
    193		goto too_early;
    194
    195	/* convert from RISC OS to Unix epoch */
    196	nsec -= nsec_unix_epoch_diff_risc_os_epoch;
    197
    198	*tv = ns_to_timespec64(nsec);
    199	return;
    200
    201 cur_time:
    202	*tv = current_time(inode);
    203	return;
    204
    205 too_early:
    206	tv->tv_sec = tv->tv_nsec = 0;
    207	return;
    208}
    209
    210/* Convert an Unix time to ADFS time for an entry that is already stamped. */
    211static void adfs_unix2adfs_time(struct inode *inode,
    212				const struct timespec64 *ts)
    213{
    214	s64 cs, nsec = timespec64_to_ns(ts);
    215
    216	/* convert from Unix to RISC OS epoch */
    217	nsec += nsec_unix_epoch_diff_risc_os_epoch;
    218
    219	/* convert from nanoseconds to centiseconds */
    220	cs = div_s64(nsec, 10000000);
    221
    222	cs = clamp_t(s64, cs, 0, 0xffffffffff);
    223
    224	ADFS_I(inode)->loadaddr &= ~0xff;
    225	ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff;
    226	ADFS_I(inode)->execaddr = cs;
    227}
    228
    229/*
    230 * Fill in the inode information from the object information.
    231 *
    232 * Note that this is an inode-less filesystem, so we can't use the inode
    233 * number to reference the metadata on the media.  Instead, we use the
    234 * inode number to hold the object ID, which in turn will tell us where
    235 * the data is held.  We also save the parent object ID, and with these
    236 * two, we can locate the metadata.
    237 *
    238 * This does mean that we rely on an objects parent remaining the same at
    239 * all times - we cannot cope with a cross-directory rename (yet).
    240 */
    241struct inode *
    242adfs_iget(struct super_block *sb, struct object_info *obj)
    243{
    244	struct inode *inode;
    245
    246	inode = new_inode(sb);
    247	if (!inode)
    248		goto out;
    249
    250	inode->i_uid	 = ADFS_SB(sb)->s_uid;
    251	inode->i_gid	 = ADFS_SB(sb)->s_gid;
    252	inode->i_ino	 = obj->indaddr;
    253	inode->i_size	 = obj->size;
    254	set_nlink(inode, 2);
    255	inode->i_blocks	 = (inode->i_size + sb->s_blocksize - 1) >>
    256			    sb->s_blocksize_bits;
    257
    258	/*
    259	 * we need to save the parent directory ID so that
    260	 * write_inode can update the directory information
    261	 * for this file.  This will need special handling
    262	 * for cross-directory renames.
    263	 */
    264	ADFS_I(inode)->parent_id = obj->parent_id;
    265	ADFS_I(inode)->indaddr   = obj->indaddr;
    266	ADFS_I(inode)->loadaddr  = obj->loadaddr;
    267	ADFS_I(inode)->execaddr  = obj->execaddr;
    268	ADFS_I(inode)->attr      = obj->attr;
    269
    270	inode->i_mode	 = adfs_atts2mode(sb, inode);
    271	adfs_adfs2unix_time(&inode->i_mtime, inode);
    272	inode->i_atime = inode->i_mtime;
    273	inode->i_ctime = inode->i_mtime;
    274
    275	if (S_ISDIR(inode->i_mode)) {
    276		inode->i_op	= &adfs_dir_inode_operations;
    277		inode->i_fop	= &adfs_dir_operations;
    278	} else if (S_ISREG(inode->i_mode)) {
    279		inode->i_op	= &adfs_file_inode_operations;
    280		inode->i_fop	= &adfs_file_operations;
    281		inode->i_mapping->a_ops = &adfs_aops;
    282		ADFS_I(inode)->mmu_private = inode->i_size;
    283	}
    284
    285	inode_fake_hash(inode);
    286
    287out:
    288	return inode;
    289}
    290
    291/*
    292 * Validate and convert a changed access mode/time to their ADFS equivalents.
    293 * adfs_write_inode will actually write the information back to the directory
    294 * later.
    295 */
    296int
    297adfs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
    298		   struct iattr *attr)
    299{
    300	struct inode *inode = d_inode(dentry);
    301	struct super_block *sb = inode->i_sb;
    302	unsigned int ia_valid = attr->ia_valid;
    303	int error;
    304	
    305	error = setattr_prepare(&init_user_ns, dentry, attr);
    306
    307	/*
    308	 * we can't change the UID or GID of any file -
    309	 * we have a global UID/GID in the superblock
    310	 */
    311	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, ADFS_SB(sb)->s_uid)) ||
    312	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, ADFS_SB(sb)->s_gid)))
    313		error = -EPERM;
    314
    315	if (error)
    316		goto out;
    317
    318	/* XXX: this is missing some actual on-disk truncation.. */
    319	if (ia_valid & ATTR_SIZE)
    320		truncate_setsize(inode, attr->ia_size);
    321
    322	if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) {
    323		adfs_unix2adfs_time(inode, &attr->ia_mtime);
    324		adfs_adfs2unix_time(&inode->i_mtime, inode);
    325	}
    326
    327	/*
    328	 * FIXME: should we make these == to i_mtime since we don't
    329	 * have the ability to represent them in our filesystem?
    330	 */
    331	if (ia_valid & ATTR_ATIME)
    332		inode->i_atime = attr->ia_atime;
    333	if (ia_valid & ATTR_CTIME)
    334		inode->i_ctime = attr->ia_ctime;
    335	if (ia_valid & ATTR_MODE) {
    336		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode, attr->ia_mode);
    337		inode->i_mode = adfs_atts2mode(sb, inode);
    338	}
    339
    340	/*
    341	 * FIXME: should we be marking this inode dirty even if
    342	 * we don't have any metadata to write back?
    343	 */
    344	if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE))
    345		mark_inode_dirty(inode);
    346out:
    347	return error;
    348}
    349
    350/*
    351 * write an existing inode back to the directory, and therefore the disk.
    352 * The adfs-specific inode data has already been updated by
    353 * adfs_notify_change()
    354 */
    355int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
    356{
    357	struct super_block *sb = inode->i_sb;
    358	struct object_info obj;
    359
    360	obj.indaddr	= ADFS_I(inode)->indaddr;
    361	obj.name_len	= 0;
    362	obj.parent_id	= ADFS_I(inode)->parent_id;
    363	obj.loadaddr	= ADFS_I(inode)->loadaddr;
    364	obj.execaddr	= ADFS_I(inode)->execaddr;
    365	obj.attr	= ADFS_I(inode)->attr;
    366	obj.size	= inode->i_size;
    367
    368	return adfs_dir_update(sb, &obj, wbc->sync_mode == WB_SYNC_ALL);
    369}