#include <sys/types.h>
#include <sys/t_lock.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/systm.h>
#include <sys/sysmacros.h>
#include <sys/resource.h>
#include <sys/signal.h>
#include <sys/cred.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/vfs.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/mode.h>
#include <sys/proc.h>
#include <sys/disp.h>
#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/flock.h>
#include <sys/kmem.h>
#include <sys/uio.h>
#include <sys/dnlc.h>
#include <sys/conf.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/fbuf.h>
#include <sys/pathname.h>
#include <sys/debug.h>
#include <sys/vmsystm.h>
#include <sys/cmn_err.h>
#include <sys/dirent.h>
#include <sys/errno.h>
#include <sys/modctl.h>
#include <sys/statvfs.h>
#include <sys/mount.h>
#include <sys/sunddi.h>
#include <sys/bootconf.h>
#include <sys/policy.h>
#include <vm/hat.h>
#include <vm/page.h>
#include <vm/pvn.h>
#include <vm/as.h>
#include <vm/seg.h>
#include <vm/seg_map.h>
#include <vm/seg_kmem.h>
#include <vm/seg_vn.h>
#include <vm/rm.h>
#include <vm/page.h>
#include <sys/swap.h>
#include <fs/fs_subr.h>
#include <sys/fs/udf_volume.h>
#include <sys/fs/udf_inode.h>
extern struct vnodeops *udf_vnodeops;
kmutex_t ud_sync_busy;
kmutex_t udf_vfs_mutex;
struct udf_vfs *udf_vfs_instances;
#ifndef __lint
_NOTE(MUTEX_PROTECTS_DATA(udf_vfs_mutex, udf_vfs_instances))
#endif
union ihead ud_ihead[UD_HASH_SZ];
kmutex_t ud_icache_lock;
#define UD_BEGIN 0x0
#define UD_END 0x1
#define UD_UNKN 0x2
struct ud_inode *udf_ifreeh, *udf_ifreet;
kmutex_t udf_ifree_lock;
#ifndef __lint
_NOTE(MUTEX_PROTECTS_DATA(udf_ifree_lock, udf_ifreeh))
_NOTE(MUTEX_PROTECTS_DATA(udf_ifree_lock, udf_ifreet))
#endif
kmutex_t ud_nino_lock;
int32_t ud_max_inodes = 512;
int32_t ud_cur_inodes = 0;
#ifndef __lint
_NOTE(MUTEX_PROTECTS_DATA(ud_nino_lock, ud_cur_inodes))
#endif
uid_t ud_default_uid = 0;
gid_t ud_default_gid = 3;
int32_t ud_updat_ext4(struct ud_inode *, struct file_entry *);
int32_t ud_updat_ext4096(struct ud_inode *, struct file_entry *);
void ud_make_sad(struct icb_ext *, struct short_ad *, int32_t);
void ud_make_lad(struct icb_ext *, struct long_ad *, int32_t);
void ud_trunc_ext4(struct ud_inode *, u_offset_t);
void ud_trunc_ext4096(struct ud_inode *, u_offset_t);
void ud_add_to_free_list(struct ud_inode *, uint32_t);
void ud_remove_from_free_list(struct ud_inode *, uint32_t);
#ifdef DEBUG
struct ud_inode *
ud_search_icache(struct vfs *vfsp, uint16_t prn, uint32_t ploc)
{
int32_t hno;
union ihead *ih;
struct ud_inode *ip;
struct udf_vfs *udf_vfsp;
uint32_t loc, dummy;
udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
loc = ud_xlate_to_daddr(udf_vfsp, prn, ploc, 1, &dummy);
mutex_enter(&ud_icache_lock);
hno = UD_INOHASH(vfsp->vfs_dev, loc);
ih = &ud_ihead[hno];
for (ip = ih->ih_chain[0];
ip != (struct ud_inode *)ih;
ip = ip->i_forw) {
if ((prn == ip->i_icb_prn) && (ploc == ip->i_icb_block) &&
(vfsp->vfs_dev == ip->i_dev)) {
mutex_exit(&ud_icache_lock);
return (ip);
}
}
mutex_exit(&ud_icache_lock);
return (0);
}
#endif
int
ud_iget(struct vfs *vfsp, uint16_t prn, uint32_t ploc, struct ud_inode **ipp,
struct buf *pbp, struct cred *cred)
{
int32_t hno, nomem = 0, icb_tag_flags;
union ihead *ih;
struct ud_inode *ip;
struct vnode *vp;
struct buf *bp = NULL;
struct file_entry *fe;
struct udf_vfs *udf_vfsp;
struct ext_attr_hdr *eah;
struct attr_hdr *ah;
int32_t ea_len, ea_off;
daddr_t loc;
uint64_t offset = 0;
struct icb_ext *iext, *con;
uint32_t length, dummy;
int32_t ndesc, ftype;
uint16_t old_prn;
uint32_t old_block, old_lbano;
ud_printf("ud_iget\n");
udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
old_prn = 0;
old_block = old_lbano = 0;
ftype = 0;
loc = ud_xlate_to_daddr(udf_vfsp, prn, ploc, 1, &dummy);
loop:
mutex_enter(&ud_icache_lock);
hno = UD_INOHASH(vfsp->vfs_dev, loc);
ih = &ud_ihead[hno];
for (ip = ih->ih_chain[0];
ip != (struct ud_inode *)ih;
ip = ip->i_forw) {
if ((prn == ip->i_icb_prn) &&
(ploc == ip->i_icb_block) &&
(vfsp->vfs_dev == ip->i_dev)) {
vp = ITOV(ip);
VN_HOLD(vp);
mutex_exit(&ud_icache_lock);
rw_enter(&ip->i_contents, RW_READER);
mutex_enter(&ip->i_tlock);
if ((ip->i_flag & IREF) == 0) {
mutex_enter(&udf_ifree_lock);
ud_remove_from_free_list(ip, UD_UNKN);
mutex_exit(&udf_ifree_lock);
}
ip->i_flag |= IREF;
mutex_exit(&ip->i_tlock);
rw_exit(&ip->i_contents);
*ipp = ip;
if (pbp != NULL) {
brelse(pbp);
}
return (0);
}
}
tryagain:
mutex_enter(&udf_ifree_lock);
mutex_enter(&ud_nino_lock);
if (ud_cur_inodes > ud_max_inodes) {
int32_t purged;
mutex_exit(&ud_nino_lock);
while (udf_ifreeh == NULL ||
vn_has_cached_data(ITOV(udf_ifreeh))) {
mutex_exit(&udf_ifree_lock);
purged = dnlc_fs_purge1(udf_vnodeops);
mutex_enter(&udf_ifree_lock);
if (!purged) {
break;
}
}
mutex_enter(&ud_nino_lock);
}
if (udf_ifreeh &&
(nomem || !vn_has_cached_data(ITOV(udf_ifreeh)) ||
ud_cur_inodes >= ud_max_inodes)) {
mutex_exit(&ud_nino_lock);
ip = udf_ifreeh;
vp = ITOV(ip);
ud_remove_from_free_list(ip, UD_BEGIN);
mutex_exit(&udf_ifree_lock);
if (ip->i_flag & IREF) {
cmn_err(CE_WARN, "ud_iget: bad i_flag\n");
mutex_exit(&ud_icache_lock);
if (pbp != NULL) {
brelse(pbp);
}
return (EINVAL);
}
rw_enter(&ip->i_contents, RW_WRITER);
mutex_enter(&ip->i_tlock);
ip->i_flag = (ip->i_flag & IMODTIME) | IREF;
mutex_exit(&ip->i_tlock);
VN_HOLD(vp);
if (ud_syncip(ip, B_INVAL, I_SYNC) != 0) {
ud_idrop(ip);
rw_exit(&ip->i_contents);
mutex_exit(&ud_icache_lock);
goto loop;
}
mutex_enter(&ip->i_tlock);
ip->i_flag &= ~IMODTIME;
mutex_exit(&ip->i_tlock);
if (ip->i_ext) {
kmem_free(ip->i_ext,
sizeof (struct icb_ext) * ip->i_ext_count);
ip->i_ext = 0;
ip->i_ext_count = ip->i_ext_used = 0;
}
if (ip->i_con) {
kmem_free(ip->i_con,
sizeof (struct icb_ext) * ip->i_con_count);
ip->i_con = 0;
ip->i_con_count = ip->i_con_used = ip->i_con_read = 0;
}
} else {
mutex_exit(&ud_nino_lock);
mutex_exit(&udf_ifree_lock);
ip = (struct ud_inode *)kmem_zalloc(sizeof (struct ud_inode),
KM_NOSLEEP);
vp = vn_alloc(KM_NOSLEEP);
if ((ip == NULL) || (vp == NULL)) {
mutex_enter(&udf_ifree_lock);
if (udf_ifreeh) {
mutex_exit(&udf_ifree_lock);
if (ip != NULL)
kmem_free(ip, sizeof (struct ud_inode));
if (vp != NULL)
vn_free(vp);
nomem = 1;
goto tryagain;
} else {
mutex_exit(&udf_ifree_lock);
if (ip == NULL)
ip = (struct ud_inode *)
kmem_zalloc(
sizeof (struct ud_inode),
KM_SLEEP);
if (vp == NULL)
vp = vn_alloc(KM_SLEEP);
}
}
ip->i_vnode = vp;
ip->i_marker1 = (uint32_t)0xAAAAAAAA;
ip->i_marker2 = (uint32_t)0xBBBBBBBB;
ip->i_marker3 = (uint32_t)0xCCCCCCCC;
rw_init(&ip->i_rwlock, NULL, RW_DEFAULT, NULL);
rw_init(&ip->i_contents, NULL, RW_DEFAULT, NULL);
mutex_init(&ip->i_tlock, NULL, MUTEX_DEFAULT, NULL);
ip->i_forw = ip;
ip->i_back = ip;
vp->v_data = (caddr_t)ip;
vn_setops(vp, udf_vnodeops);
ip->i_flag = IREF;
cv_init(&ip->i_wrcv, NULL, CV_DRIVER, NULL);
mutex_enter(&ud_nino_lock);
ud_cur_inodes++;
mutex_exit(&ud_nino_lock);
rw_enter(&ip->i_contents, RW_WRITER);
}
if (vp->v_count < 1) {
cmn_err(CE_WARN, "ud_iget: v_count < 1\n");
mutex_exit(&ud_icache_lock);
rw_exit(&ip->i_contents);
if (pbp != NULL) {
brelse(pbp);
}
return (EINVAL);
}
if (vn_has_cached_data(vp)) {
cmn_err(CE_WARN, "ud_iget: v_pages not NULL\n");
mutex_exit(&ud_icache_lock);
rw_exit(&ip->i_contents);
if (pbp != NULL) {
brelse(pbp);
}
return (EINVAL);
}
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
insque(ip, ih);
ip->i_dev = vfsp->vfs_dev;
ip->i_udf = udf_vfsp;
ip->i_diroff = 0;
ip->i_devvp = ip->i_udf->udf_devvp;
ip->i_icb_prn = prn;
ip->i_icb_block = ploc;
ip->i_icb_lbano = loc;
ip->i_nextr = 0;
ip->i_seq = 0;
mutex_exit(&ud_icache_lock);
read_de:
if (pbp != NULL) {
bp = pbp;
} else {
bp = ud_bread(ip->i_dev,
ip->i_icb_lbano << udf_vfsp->udf_l2d_shift,
udf_vfsp->udf_lbsize);
}
fe = (struct file_entry *)bp->b_un.b_addr;
if ((bp->b_flags & B_ERROR) ||
(ud_verify_tag_and_desc(&fe->fe_tag, UD_FILE_ENTRY,
ip->i_icb_block, 1, udf_vfsp->udf_lbsize) != 0)) {
if (((bp->b_flags & B_ERROR) == 0) &&
(ftype == STRAT_TYPE4096)) {
if (ud_check_te_unrec(udf_vfsp,
bp->b_un.b_addr, ip->i_icb_block) == 0) {
brelse(bp);
ip->i_icb_prn = old_prn;
ip->i_icb_block = old_block;
ip->i_icb_lbano = old_lbano;
bp = ud_bread(ip->i_dev,
old_lbano << udf_vfsp->udf_l2d_shift,
udf_vfsp->udf_lbsize);
if ((bp->b_flags & B_ERROR) == 0) {
fe = (struct file_entry *)
bp->b_un.b_addr;
if (ud_verify_tag_and_desc(&fe->fe_tag,
UD_FILE_ENTRY, ip->i_icb_block, 1,
udf_vfsp->udf_lbsize) == 0) {
goto end_4096;
}
}
}
}
error_ret:
brelse(bp);
mutex_enter(&vp->v_lock);
VN_RELE_LOCKED(vp);
mutex_exit(&vp->v_lock);
ip->i_icb_lbano = 0;
ip->i_icb_prn = 0xffff;
ip->i_icb_block = 0;
mutex_enter(&ud_icache_lock);
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
mutex_exit(&ud_icache_lock);
mutex_enter(&ip->i_tlock);
mutex_enter(&udf_ifree_lock);
ud_add_to_free_list(ip, UD_BEGIN);
mutex_exit(&udf_ifree_lock);
ip->i_flag = 0;
mutex_exit(&ip->i_tlock);
rw_exit(&ip->i_contents);
return (EIO);
}
if (fe->fe_icb_tag.itag_strategy == SWAP_16(STRAT_TYPE4096)) {
struct buf *ibp = NULL;
struct indirect_entry *ie;
old_prn = ip->i_icb_prn;
old_block = ip->i_icb_block;
old_lbano = ip->i_icb_lbano;
ftype = STRAT_TYPE4096;
ibp = ud_bread(ip->i_dev,
(ip->i_icb_lbano + 1) << udf_vfsp->udf_l2d_shift,
udf_vfsp->udf_lbsize);
if (ibp->b_flags & B_ERROR) {
ie_error:
brelse(ibp);
goto error_ret;
}
ie = (struct indirect_entry *)ibp->b_un.b_addr;
if (ud_verify_tag_and_desc(&ie->ie_tag,
UD_INDIRECT_ENT, ip->i_icb_block + 1,
1, udf_vfsp->udf_lbsize) == 0) {
struct long_ad *lad;
lad = &ie->ie_indirecticb;
ip->i_icb_prn = SWAP_16(lad->lad_ext_prn);
ip->i_icb_block = SWAP_32(lad->lad_ext_loc);
ip->i_icb_lbano = ud_xlate_to_daddr(udf_vfsp,
ip->i_icb_prn, ip->i_icb_block,
1, &dummy);
brelse(ibp);
brelse(bp);
goto read_de;
}
if (ud_check_te_unrec(udf_vfsp, ibp->b_un.b_addr,
ip->i_icb_block + 1) != 0) {
goto ie_error;
}
brelse(ibp);
}
end_4096:
ip->i_uid = SWAP_32(fe->fe_uid);
if (ip->i_uid == -1) {
ip->i_uid = ud_default_uid;
}
ip->i_gid = SWAP_32(fe->fe_gid);
if (ip->i_gid == -1) {
ip->i_gid = ud_default_gid;
}
ip->i_perm = SWAP_32(fe->fe_perms) & 0xFFFF;
if (fe->fe_icb_tag.itag_strategy == SWAP_16(STRAT_TYPE4096)) {
ip->i_perm &= ~(IWRITE | (IWRITE >> 5) | (IWRITE >> 10));
}
ip->i_nlink = SWAP_16(fe->fe_lcount);
ip->i_size = SWAP_64(fe->fe_info_len);
ip->i_lbr = SWAP_64(fe->fe_lbr);
ud_dtime2utime(&ip->i_atime, &fe->fe_acc_time);
ud_dtime2utime(&ip->i_mtime, &fe->fe_mod_time);
ud_dtime2utime(&ip->i_ctime, &fe->fe_attr_time);
ip->i_uniqid = SWAP_64(fe->fe_uniq_id);
icb_tag_flags = SWAP_16(fe->fe_icb_tag.itag_flags);
if ((fe->fe_icb_tag.itag_ftype == FTYPE_CHAR_DEV) ||
(fe->fe_icb_tag.itag_ftype == FTYPE_BLOCK_DEV)) {
eah = (struct ext_attr_hdr *)fe->fe_spec;
ea_off = GET_32(&eah->eah_ial);
ea_len = GET_32(&fe->fe_len_ear);
if (ea_len && (ud_verify_tag_and_desc(&eah->eah_tag,
UD_EXT_ATTR_HDR, ip->i_icb_block, 1,
sizeof (struct file_entry) -
offsetof(struct file_entry, fe_spec)) == 0)) {
while (ea_off < ea_len) {
if ((ea_len - ea_off) <
sizeof (struct attr_hdr)) {
cmn_err(CE_NOTE,
"ea_len(0x%x) - ea_off(0x%x) is "
"too small to hold attr. info. "
"blockno 0x%x\n",
ea_len, ea_off, ip->i_icb_block);
goto error_ret;
}
ah = (struct attr_hdr *)&fe->fe_spec[ea_off];
if ((GET_32(&ah->ahdr_atype) == 12) &&
(ah->ahdr_astype == 1)) {
struct dev_spec_ear *ds;
if ((ea_len - ea_off) <
sizeof (struct dev_spec_ear)) {
cmn_err(CE_NOTE,
"ea_len(0x%x) - "
"ea_off(0x%x) is too small "
"to hold dev_spec_ear."
" blockno 0x%x\n",
ea_len, ea_off,
ip->i_icb_block);
goto error_ret;
}
ds = (struct dev_spec_ear *)ah;
ip->i_major = GET_32(&ds->ds_major_id);
ip->i_minor = GET_32(&ds->ds_minor_id);
}
if ((GET_32(&ah->ahdr_atype) == 2048) &&
(ah->ahdr_astype == 1)) {
struct iu_ea *iuea;
struct copy_mgt_info *cmi;
if ((ea_len - ea_off) <
sizeof (struct iu_ea)) {
cmn_err(CE_NOTE,
"ea_len(0x%x) - ea_off(0x%x) is too small to hold iu_ea. blockno 0x%x\n",
ea_len, ea_off,
ip->i_icb_block);
goto error_ret;
}
iuea = (struct iu_ea *)ah;
if (strncmp(iuea->iuea_ii.reg_id,
UDF_FREEEASPACE,
sizeof (iuea->iuea_ii.reg_id))
== 0) {
iuea = iuea;
} else if (strncmp(iuea->iuea_ii.reg_id,
UDF_CGMS_INFO,
sizeof (iuea->iuea_ii.reg_id))
== 0) {
cmi = (struct copy_mgt_info *)
iuea->iuea_iu;
cmi = cmi;
}
}
if (GET_32(&ah->ahdr_length) == 0) {
break;
}
ea_off += GET_32(&ah->ahdr_length);
}
}
}
ip->i_nextr = 0;
ip->i_maxent = SWAP_16(fe->fe_icb_tag.itag_max_ent);
ip->i_astrat = SWAP_16(fe->fe_icb_tag.itag_strategy);
ip->i_desc_type = icb_tag_flags & 0x7;
ip->i_ext = NULL;
ip->i_ext_count = ip->i_ext_used = 0;
ip->i_con = 0;
ip->i_con_count = ip->i_con_used = ip->i_con_read = 0;
ip->i_data_off = 0xB0 + SWAP_32(fe->fe_len_ear);
ip->i_max_emb = udf_vfsp->udf_lbsize - ip->i_data_off;
if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
struct short_ad *sad;
ip->i_ext_used = 0;
ip->i_ext_count = ndesc =
SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
ip->i_ext_count =
((ip->i_ext_count / EXT_PER_MALLOC) + 1) * EXT_PER_MALLOC;
ip->i_ext = (struct icb_ext *)kmem_zalloc(ip->i_ext_count *
sizeof (struct icb_ext), KM_SLEEP);
ip->i_cur_max_ext = ip->i_max_emb / sizeof (struct short_ad);
ip->i_cur_max_ext --;
if ((ip->i_astrat != STRAT_TYPE4) &&
(ip->i_astrat != STRAT_TYPE4096)) {
goto error_ret;
}
sad = (struct short_ad *)
(fe->fe_spec + SWAP_32(fe->fe_len_ear));
iext = ip->i_ext;
while (ndesc --) {
length = SWAP_32(sad->sad_ext_len);
if ((length & 0x3FFFFFFF) == 0) {
break;
}
if (((length >> 30) & IB_MASK) == IB_CON) {
if (ip->i_con == NULL) {
ip->i_con_count = EXT_PER_MALLOC;
ip->i_con_used = 0;
ip->i_con_read = 0;
ip->i_con = kmem_zalloc(
ip->i_con_count *
sizeof (struct icb_ext),
KM_SLEEP);
}
con = &ip->i_con[ip->i_con_used];
con->ib_prn = 0;
con->ib_block = SWAP_32(sad->sad_ext_loc);
con->ib_count = length & 0x3FFFFFFF;
con->ib_flags = (length >> 30) & IB_MASK;
ip->i_con_used++;
sad ++;
break;
}
iext->ib_prn = 0;
iext->ib_block = SWAP_32(sad->sad_ext_loc);
length = SWAP_32(sad->sad_ext_len);
iext->ib_count = length & 0x3FFFFFFF;
iext->ib_offset = offset;
iext->ib_marker1 = (uint32_t)0xAAAAAAAA;
iext->ib_marker2 = (uint32_t)0xBBBBBBBB;
offset += (iext->ib_count + udf_vfsp->udf_lbmask) &
(~udf_vfsp->udf_lbmask);
iext->ib_flags = (length >> 30) & IB_MASK;
ip->i_ext_used++;
iext++;
sad ++;
}
} else if (ip->i_desc_type == ICB_FLAG_LONG_AD) {
struct long_ad *lad;
ip->i_ext_used = 0;
ip->i_ext_count = ndesc =
SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
ip->i_ext_count =
((ip->i_ext_count / EXT_PER_MALLOC) + 1) * EXT_PER_MALLOC;
ip->i_ext = (struct icb_ext *)kmem_zalloc(ip->i_ext_count *
sizeof (struct icb_ext), KM_SLEEP);
ip->i_cur_max_ext = ip->i_max_emb / sizeof (struct long_ad);
ip->i_cur_max_ext --;
if ((ip->i_astrat != STRAT_TYPE4) &&
(ip->i_astrat != STRAT_TYPE4096)) {
goto error_ret;
}
lad = (struct long_ad *)
(fe->fe_spec + SWAP_32(fe->fe_len_ear));
iext = ip->i_ext;
while (ndesc --) {
length = SWAP_32(lad->lad_ext_len);
if ((length & 0x3FFFFFFF) == 0) {
break;
}
if (((length >> 30) & IB_MASK) == IB_CON) {
if (ip->i_con == NULL) {
ip->i_con_count = EXT_PER_MALLOC;
ip->i_con_used = 0;
ip->i_con_read = 0;
ip->i_con = kmem_zalloc(
ip->i_con_count *
sizeof (struct icb_ext),
KM_SLEEP);
}
con = &ip->i_con[ip->i_con_used];
con->ib_prn = SWAP_16(lad->lad_ext_prn);
con->ib_block = SWAP_32(lad->lad_ext_loc);
con->ib_count = length & 0x3FFFFFFF;
con->ib_flags = (length >> 30) & IB_MASK;
ip->i_con_used++;
lad ++;
break;
}
iext->ib_prn = SWAP_16(lad->lad_ext_prn);
iext->ib_block = SWAP_32(lad->lad_ext_loc);
iext->ib_count = length & 0x3FFFFFFF;
iext->ib_offset = offset;
iext->ib_marker1 = (uint32_t)0xAAAAAAAA;
iext->ib_marker2 = (uint32_t)0xBBBBBBBB;
offset += (iext->ib_count + udf_vfsp->udf_lbmask) &
(~udf_vfsp->udf_lbmask);
iext->ib_flags = (length >> 30) & IB_MASK;
ip->i_ext_used++;
iext++;
lad ++;
}
} else if (ip->i_desc_type == ICB_FLAG_ONE_AD) {
ASSERT(SWAP_32(fe->fe_len_ear) < udf_vfsp->udf_lbsize);
if (SWAP_32(fe->fe_len_ear) > udf_vfsp->udf_lbsize) {
goto error_ret;
}
} else {
cmn_err(CE_NOTE, "Invalid Allocation Descriptor type %x\n",
ip->i_desc_type);
goto error_ret;
}
if (icb_tag_flags & ICB_FLAG_SETUID) {
ip->i_char = ISUID;
} else {
ip->i_char = 0;
}
if (icb_tag_flags & ICB_FLAG_SETGID) {
ip->i_char |= ISGID;
}
if (icb_tag_flags & ICB_FLAG_STICKY) {
ip->i_char |= ISVTX;
}
switch (fe->fe_icb_tag.itag_ftype) {
case FTYPE_DIRECTORY :
ip->i_type = VDIR;
break;
case FTYPE_FILE :
ip->i_type = VREG;
break;
case FTYPE_BLOCK_DEV :
ip->i_type = VBLK;
break;
case FTYPE_CHAR_DEV :
ip->i_type = VCHR;
break;
case FTYPE_FIFO :
ip->i_type = VFIFO;
break;
case FTYPE_C_ISSOCK :
ip->i_type = VSOCK;
break;
case FTYPE_SYMLINK :
ip->i_type = VLNK;
break;
default :
ip->i_type = VNON;
break;
}
if (ip->i_type == VBLK || ip->i_type == VCHR) {
ip->i_rdev = makedevice(ip->i_major, ip->i_minor);
}
vp->v_vfsp = vfsp;
vp->v_type = ip->i_type;
vp->v_rdev = ip->i_rdev;
if (ip->i_udf->udf_root_blkno == loc) {
vp->v_flag = VROOT;
} else {
vp->v_flag = 0;
}
brelse(bp);
*ipp = ip;
rw_exit(&ip->i_contents);
vn_exists(vp);
return (0);
}
void
ud_iinactive(struct ud_inode *ip, struct cred *cr)
{
int32_t busy = 0;
struct vnode *vp;
vtype_t type;
caddr_t addr, addr1;
size_t size, size1;
ud_printf("ud_iinactive\n");
rw_enter(&ip->i_contents, RW_WRITER);
vp = ITOV(ip);
mutex_enter(&vp->v_lock);
if (vp->v_count < 1) {
cmn_err(CE_WARN, "ud_iinactive: v_count < 1\n");
return;
}
if ((vp->v_count > 1) || ((ip->i_flag & IREF) == 0)) {
VN_RELE_LOCKED(vp);
mutex_exit(&vp->v_lock);
rw_exit(&ip->i_contents);
return;
}
mutex_exit(&vp->v_lock);
if (ip->i_udf == NULL) {
addr = (caddr_t)ip->i_ext;
size = sizeof (struct icb_ext) * ip->i_ext_count;
ip->i_ext = 0;
ip->i_ext_count = ip->i_ext_used = 0;
addr1 = (caddr_t)ip->i_con;
size1 = sizeof (struct icb_ext) * ip->i_con_count;
ip->i_con = 0;
ip->i_con_count = ip->i_con_used = ip->i_con_read = 0;
rw_exit(&ip->i_contents);
vn_invalid(vp);
mutex_enter(&ud_nino_lock);
ud_cur_inodes--;
mutex_exit(&ud_nino_lock);
cv_destroy(&ip->i_wrcv);
rw_destroy(&ip->i_rwlock);
rw_exit(&ip->i_contents);
rw_destroy(&ip->i_contents);
kmem_free(addr, size);
kmem_free(addr1, size1);
vn_free(vp);
kmem_free(ip, sizeof (struct ud_inode));
return;
}
if ((ip->i_udf->udf_flags & UDF_FL_RDONLY) == 0) {
if (ip->i_nlink <= 0) {
ip->i_marker3 = (uint32_t)0xDDDD0000;
ip->i_nlink = 1;
(void) ud_itrunc(ip, 0, 0, cr);
type = ip->i_type;
ip->i_perm = 0;
ip->i_uid = 0;
ip->i_gid = 0;
ip->i_rdev = 0;
mutex_enter(&ip->i_tlock);
ip->i_flag |= IUPD|ICHG;
mutex_exit(&ip->i_tlock);
ud_ifree(ip, type);
ip->i_icb_prn = 0xFFFF;
} else if (!IS_SWAPVP(vp)) {
(void) ud_syncip(ip, B_FREE | B_ASYNC, 0);
mutex_enter(&vp->v_lock);
if (vp->v_count > 1) {
VN_RELE_LOCKED(vp);
mutex_exit(&vp->v_lock);
rw_exit(&ip->i_contents);
return;
}
mutex_exit(&vp->v_lock);
} else {
ud_iupdat(ip, 0);
}
}
tryagain:
mutex_enter(&ud_nino_lock);
if (vn_has_cached_data(vp)) {
mutex_exit(&ud_nino_lock);
mutex_enter(&vp->v_lock);
VN_RELE_LOCKED(vp);
mutex_exit(&vp->v_lock);
mutex_enter(&ip->i_tlock);
mutex_enter(&udf_ifree_lock);
ud_add_to_free_list(ip, UD_END);
mutex_exit(&udf_ifree_lock);
ip->i_flag &= IMODTIME;
mutex_exit(&ip->i_tlock);
rw_exit(&ip->i_contents);
} else if (busy || ud_cur_inodes < ud_max_inodes) {
mutex_exit(&ud_nino_lock);
mutex_enter(&vp->v_lock);
if (vn_has_cached_data(vp)) {
cmn_err(CE_WARN, "ud_iinactive: v_pages not NULL\n");
}
VN_RELE_LOCKED(vp);
mutex_exit(&vp->v_lock);
mutex_enter(&ip->i_tlock);
mutex_enter(&udf_ifree_lock);
ud_add_to_free_list(ip, UD_BEGIN);
mutex_exit(&udf_ifree_lock);
ip->i_flag &= IMODTIME;
mutex_exit(&ip->i_tlock);
rw_exit(&ip->i_contents);
} else {
mutex_exit(&ud_nino_lock);
if (vn_has_cached_data(vp)) {
cmn_err(CE_WARN, "ud_iinactive: v_pages not NULL\n");
}
if (!mutex_tryenter(&ud_icache_lock)) {
busy = 1;
goto tryagain;
}
mutex_enter(&vp->v_lock);
if (vp->v_count > 1) {
busy = 1;
mutex_exit(&vp->v_lock);
mutex_exit(&ud_icache_lock);
goto tryagain;
}
mutex_exit(&vp->v_lock);
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
mutex_enter(&ud_nino_lock);
ud_cur_inodes--;
mutex_exit(&ud_nino_lock);
mutex_exit(&ud_icache_lock);
if (ip->i_icb_prn != 0xFFFF) {
ud_iupdat(ip, 0);
}
addr = (caddr_t)ip->i_ext;
size = sizeof (struct icb_ext) * ip->i_ext_count;
ip->i_ext = 0;
ip->i_ext_count = ip->i_ext_used = 0;
addr1 = (caddr_t)ip->i_con;
size1 = sizeof (struct icb_ext) * ip->i_con_count;
ip->i_con = 0;
ip->i_con_count = ip->i_con_used = ip->i_con_read = 0;
cv_destroy(&ip->i_wrcv);
rw_destroy(&ip->i_rwlock);
rw_exit(&ip->i_contents);
rw_destroy(&ip->i_contents);
kmem_free(addr, size);
kmem_free(addr1, size1);
ip->i_marker3 = (uint32_t)0xDDDDDDDD;
vn_free(vp);
kmem_free(ip, sizeof (struct ud_inode));
}
}
void
ud_iupdat(struct ud_inode *ip, int32_t waitfor)
{
uint16_t flag, tag_flags;
int32_t error;
struct buf *bp;
struct udf_vfs *udf_vfsp;
struct file_entry *fe;
uint16_t crc_len = 0;
ASSERT(RW_WRITE_HELD(&ip->i_contents));
ud_printf("ud_iupdat\n");
if (ip->i_udf == NULL) {
return;
}
udf_vfsp = ip->i_udf;
flag = ip->i_flag;
if ((flag & (IUPD|IACC|ICHG|IMOD|IMODACC)) != 0) {
if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD|IMODACC|IATTCHG);
return;
}
bp = ud_bread(ip->i_dev,
ip->i_icb_lbano << udf_vfsp->udf_l2d_shift,
ip->i_udf->udf_lbsize);
if (bp->b_flags & B_ERROR) {
brelse(bp);
return;
}
fe = (struct file_entry *)bp->b_un.b_addr;
if (ud_verify_tag_and_desc(&fe->fe_tag, UD_FILE_ENTRY,
ip->i_icb_block,
1, ip->i_udf->udf_lbsize) != 0) {
brelse(bp);
return;
}
mutex_enter(&ip->i_tlock);
if (ip->i_flag & (IUPD|IACC|ICHG)) {
IMARK(ip);
}
ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD|IMODACC);
mutex_exit(&ip->i_tlock);
fe->fe_uid = SWAP_32(ip->i_uid);
fe->fe_gid = SWAP_32(ip->i_gid);
fe->fe_perms = SWAP_32(ip->i_perm);
fe->fe_lcount = SWAP_16(ip->i_nlink);
fe->fe_info_len = SWAP_64(ip->i_size);
fe->fe_lbr = SWAP_64(ip->i_lbr);
ud_utime2dtime(&ip->i_atime, &fe->fe_acc_time);
ud_utime2dtime(&ip->i_mtime, &fe->fe_mod_time);
ud_utime2dtime(&ip->i_ctime, &fe->fe_attr_time);
if (ip->i_char & ISUID) {
tag_flags = ICB_FLAG_SETUID;
} else {
tag_flags = 0;
}
if (ip->i_char & ISGID) {
tag_flags |= ICB_FLAG_SETGID;
}
if (ip->i_char & ISVTX) {
tag_flags |= ICB_FLAG_STICKY;
}
tag_flags |= ip->i_desc_type;
fe->fe_icb_tag.itag_flags &= ~SWAP_16((uint16_t)0x3C3);
fe->fe_icb_tag.itag_strategy = SWAP_16(ip->i_astrat);
fe->fe_icb_tag.itag_flags |= SWAP_16(tag_flags);
ud_update_regid(&fe->fe_impl_id);
crc_len = offsetof(struct file_entry, fe_spec) +
SWAP_32(fe->fe_len_ear);
if (ip->i_desc_type == ICB_FLAG_ONE_AD) {
crc_len += ip->i_size;
fe->fe_len_adesc = SWAP_32(((uint32_t)ip->i_size));
} else if ((ip->i_size != 0) && (ip->i_ext != NULL) &&
(ip->i_ext_used != 0)) {
if ((error = ud_read_icb_till_off(ip,
ip->i_size)) == 0) {
if (ip->i_astrat == STRAT_TYPE4) {
error = ud_updat_ext4(ip, fe);
} else if (ip->i_astrat == STRAT_TYPE4096) {
error = ud_updat_ext4096(ip, fe);
}
if (error) {
udf_vfsp->udf_mark_bad = 1;
}
}
crc_len += SWAP_32(fe->fe_len_adesc);
} else {
fe->fe_len_adesc = 0;
}
bzero(bp->b_un.b_addr + crc_len,
ip->i_udf->udf_lbsize - crc_len);
ud_make_tag(ip->i_udf, &fe->fe_tag,
UD_FILE_ENTRY, ip->i_icb_block, crc_len);
if (waitfor) {
BWRITE(bp);
ip->i_flag &= ~(IBDWRITE);
} else {
bdwrite(bp);
ip->i_flag |= (IBDWRITE);
}
} else {
if (waitfor && (flag & IBDWRITE)) {
blkflush(ip->i_dev,
(daddr_t)fsbtodb(udf_vfsp, ip->i_icb_lbano));
ip->i_flag &= ~(IBDWRITE);
}
}
}
int32_t
ud_updat_ext4(struct ud_inode *ip, struct file_entry *fe)
{
uint32_t dummy;
int32_t elen, ndent, index, count, con_index;
daddr_t bno;
struct buf *bp;
struct short_ad *sad;
struct long_ad *lad;
struct icb_ext *iext, *icon;
ASSERT(ip);
ASSERT(fe);
ASSERT((ip->i_desc_type == ICB_FLAG_SHORT_AD) ||
(ip->i_desc_type == ICB_FLAG_LONG_AD));
if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
elen = sizeof (struct short_ad);
sad = (struct short_ad *)
(fe->fe_spec + SWAP_32(fe->fe_len_ear));
} else if (ip->i_desc_type == ICB_FLAG_LONG_AD) {
elen = sizeof (struct long_ad);
lad = (struct long_ad *)
(fe->fe_spec + SWAP_32(fe->fe_len_ear));
} else {
return (EINVAL);
}
ndent = ip->i_max_emb / elen;
if (ip->i_ext_used < ndent) {
if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
ud_make_sad(ip->i_ext, sad, ip->i_ext_used);
} else {
ud_make_lad(ip->i_ext, lad, ip->i_ext_used);
}
fe->fe_len_adesc = SWAP_32(ip->i_ext_used * elen);
con_index = 0;
} else {
con_index = index = 0;
while (index < ip->i_ext_used) {
if (index == 0) {
count = ndent - 1;
fe->fe_len_adesc = SWAP_32(ndent * elen);
bp = NULL;
icon = &ip->i_con[con_index];
} else {
icon = &ip->i_con[con_index];
bno = ud_xlate_to_daddr(ip->i_udf,
icon->ib_prn, icon->ib_block,
icon->ib_count >> ip->i_udf->udf_l2d_shift,
&dummy);
bp = ud_bread(ip->i_dev,
bno << ip->i_udf->udf_l2d_shift,
ip->i_udf->udf_lbsize);
if (bp->b_flags & B_ERROR) {
brelse(bp);
return (EIO);
}
count = (bp->b_bcount -
sizeof (struct alloc_ext_desc)) / elen;
if (count > (ip->i_ext_used - index)) {
count = ip->i_ext_used - index;
} else {
count --;
}
con_index++;
if (con_index >= ip->i_con_used) {
icon = NULL;
} else {
icon = &ip->i_con[con_index];
}
}
iext = &ip->i_ext[index];
if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
if (index != 0) {
sad = (struct short_ad *)
(bp->b_un.b_addr +
sizeof (struct alloc_ext_desc));
}
ud_make_sad(iext, sad, count);
sad += count;
if (icon != NULL) {
ud_make_sad(icon, sad, 1);
}
} else {
if (index != 0) {
lad = (struct long_ad *)
(bp->b_un.b_addr +
sizeof (struct alloc_ext_desc));
}
ud_make_lad(iext, lad, count);
lad += count;
if (icon != NULL) {
ud_make_lad(icon, lad, 1);
}
}
if (con_index != 0) {
struct alloc_ext_desc *aed;
int32_t sz;
struct icb_ext *oicon;
oicon = &ip->i_con[con_index - 1];
sz = count * elen;
if (icon != NULL) {
sz += elen;
}
aed = (struct alloc_ext_desc *)bp->b_un.b_addr;
aed->aed_len_aed = SWAP_32(sz);
if (con_index == 1) {
aed->aed_rev_ael =
SWAP_32(ip->i_icb_block);
} else {
aed->aed_rev_ael =
SWAP_32(oicon->ib_block);
}
sz += sizeof (struct alloc_ext_desc);
ud_make_tag(ip->i_udf, &aed->aed_tag,
UD_ALLOC_EXT_DESC, oicon->ib_block, sz);
}
if (bp != NULL) {
BWRITE(bp);
}
index += count;
}
}
if (con_index != ip->i_con_used) {
int32_t lbmask, l2b, temp;
temp = con_index;
lbmask = ip->i_udf->udf_lbmask;
l2b = ip->i_udf->udf_l2b_shift;
for (; con_index < ip->i_con_used; con_index++) {
icon = &ip->i_con[con_index];
count = (icon->ib_count + lbmask) >> l2b;
ud_free_space(ip->i_udf->udf_vfs, icon->ib_prn,
icon->ib_block, count);
count = (count << l2b) - sizeof (struct alloc_ext_desc);
ip->i_cur_max_ext -= (count / elen) - 1;
}
ip->i_con_used = temp;
}
return (0);
}
int32_t
ud_updat_ext4096(struct ud_inode *ip, struct file_entry *fe)
{
return (ENXIO);
}
void
ud_make_sad(struct icb_ext *iext, struct short_ad *sad, int32_t count)
{
int32_t index = 0, scount;
ASSERT(iext);
ASSERT(sad);
if (count != 0) {
ASSERT(count > 0);
while (index < count) {
scount = (iext->ib_count & 0x3FFFFFFF) |
(iext->ib_flags << 30);
sad->sad_ext_len = SWAP_32(scount);
sad->sad_ext_loc = SWAP_32(iext->ib_block);
sad++;
iext++;
index++;
}
}
}
void
ud_make_lad(struct icb_ext *iext, struct long_ad *lad, int32_t count)
{
int32_t index = 0, scount;
ASSERT(iext);
ASSERT(lad);
if (count != 0) {
ASSERT(count > 0);
while (index < count) {
lad->lad_ext_prn = SWAP_16(iext->ib_prn);
scount = (iext->ib_count & 0x3FFFFFFF) |
(iext->ib_flags << 30);
lad->lad_ext_len = SWAP_32(scount);
lad->lad_ext_loc = SWAP_32(iext->ib_block);
lad++;
iext++;
index++;
}
}
}
int
ud_itrunc(struct ud_inode *oip, u_offset_t length,
int32_t flags, struct cred *cr)
{
int32_t error, boff;
off_t bsize;
mode_t mode;
struct udf_vfs *udf_vfsp;
ud_printf("ud_itrunc\n");
ASSERT(RW_WRITE_HELD(&oip->i_contents));
udf_vfsp = oip->i_udf;
bsize = udf_vfsp->udf_lbsize;
mode = oip->i_type;
if (mode == VFIFO) {
return (0);
}
if ((mode != VREG) && (mode != VDIR) &&
(!(mode == VLNK && length == 0))) {
return (EINVAL);
}
if (length == oip->i_size) {
mutex_enter(&oip->i_tlock);
oip->i_flag |= ICHG |IUPD;
mutex_exit(&oip->i_tlock);
return (0);
}
boff = blkoff(udf_vfsp, length);
if (length > oip->i_size) {
if (boff == 0) {
error = ud_bmap_write(oip, length - 1,
(int)bsize, 0, cr);
} else {
error = ud_bmap_write(oip, length - 1, boff, 0, cr);
}
if (error == 0) {
u_offset_t osize = oip->i_size;
oip->i_size = length;
if ((boff = blkoff(udf_vfsp, osize)) != 0) {
pvn_vpzero(ITOV(oip), osize,
(uint32_t)(bsize - boff));
}
mutex_enter(&oip->i_tlock);
oip->i_flag |= ICHG;
ITIMES_NOLOCK(oip);
mutex_exit(&oip->i_tlock);
}
return (error);
}
if (boff == 0) {
(void) pvn_vplist_dirty(ITOV(oip), length,
ud_putapage, B_INVAL | B_TRUNC, CRED());
} else {
error = ud_bmap_write(oip, length - 1, boff, 0, cr);
if (error) {
return (error);
}
pvn_vpzero(ITOV(oip), length, (uint32_t)(bsize - boff));
(void) pvn_vplist_dirty(ITOV(oip), length,
ud_putapage, B_INVAL | B_TRUNC, CRED());
}
if (oip->i_desc_type == ICB_FLAG_ONE_AD) {
if (length > oip->i_max_emb) {
return (EFBIG);
}
oip->i_size = length;
mutex_enter(&oip->i_tlock);
oip->i_flag |= ICHG|IUPD;
mutex_exit(&oip->i_tlock);
ud_iupdat(oip, 1);
} else {
if ((error = ud_read_icb_till_off(oip, oip->i_size)) != 0) {
return (error);
}
if (oip->i_astrat == STRAT_TYPE4) {
ud_trunc_ext4(oip, length);
} else if (oip->i_astrat == STRAT_TYPE4096) {
ud_trunc_ext4096(oip, length);
}
}
return (0);
}
void
ud_trunc_ext4(struct ud_inode *ip, u_offset_t length)
{
int32_t index, l2b, count, ecount;
int32_t elen, ndent, nient;
u_offset_t ext_beg, ext_end;
struct icb_ext *iext, *icon;
int32_t lbmask, ext_used;
uint32_t loc;
struct icb_ext text;
uint32_t con_freed;
ASSERT((ip->i_desc_type == ICB_FLAG_SHORT_AD) ||
(ip->i_desc_type == ICB_FLAG_LONG_AD));
if (ip->i_ext_used == 0) {
return;
}
ext_used = ip->i_ext_used;
lbmask = ip->i_udf->udf_lbmask;
l2b = ip->i_udf->udf_l2b_shift;
ASSERT(ip->i_ext);
ip->i_lbr = 0;
for (index = 0; index < ext_used; index++) {
iext = &ip->i_ext[index];
ext_beg = iext->ib_offset;
ext_end = iext->ib_offset +
((iext->ib_count + lbmask) & ~lbmask);
if ((length <= ext_end) && (length >= ext_beg)) {
text = *iext;
iext->ib_count = length - ext_beg;
ip->i_ext_used = index + 1;
break;
}
if (iext->ib_flags != IB_UN_RE_AL) {
ip->i_lbr += iext->ib_count >> l2b;
}
}
if (ip->i_ext_used != index) {
if (iext->ib_flags != IB_UN_RE_AL) {
ip->i_lbr +=
((iext->ib_count + lbmask) & ~lbmask) >> l2b;
}
}
ip->i_size = length;
mutex_enter(&ip->i_tlock);
ip->i_flag |= ICHG|IUPD;
mutex_exit(&ip->i_tlock);
ud_iupdat(ip, 1);
if (text.ib_flags != IB_UN_RE_AL) {
count = (ext_end - length) >> l2b;
if (count) {
loc = text.ib_block +
(((length - text.ib_offset) + lbmask) >> l2b);
ud_free_space(ip->i_udf->udf_vfs, text.ib_prn,
loc, count);
}
}
for (index = ip->i_ext_used; index < ext_used; index++) {
iext = &ip->i_ext[index];
if (iext->ib_flags != IB_UN_RE_AL) {
count = (iext->ib_count + lbmask) >> l2b;
ud_free_space(ip->i_udf->udf_vfs, iext->ib_prn,
iext->ib_block, count);
}
bzero(iext, sizeof (struct icb_ext));
continue;
}
if (ip->i_con) {
ASSERT(ip->i_con_count >= ip->i_con_used);
if (ip->i_desc_type == ICB_FLAG_SHORT_AD) {
elen = sizeof (struct short_ad);
} else if (ip->i_desc_type == ICB_FLAG_LONG_AD) {
elen = sizeof (struct long_ad);
}
ndent = ip->i_max_emb / elen;
if (ip->i_ext_used > ndent) {
ecount = ip->i_ext_used - ndent;
} else {
ecount = 0;
}
con_freed = 0;
for (index = 0; index < ip->i_con_used; index++) {
icon = &ip->i_con[index];
nient = icon->ib_count -
(sizeof (struct alloc_ext_desc) + elen);
nient /= elen;
if (ecount) {
if (ecount > nient) {
ecount -= nient;
} else {
ecount = 0;
}
} else {
count = ((icon->ib_count + lbmask) &
~lbmask) >> l2b;
ud_free_space(ip->i_udf->udf_vfs,
icon->ib_prn, icon->ib_block, count);
con_freed++;
ip->i_cur_max_ext -= nient;
}
}
ip->i_con_used -= con_freed;
if (ip->i_con_read > ip->i_con_used) {
ip->i_con_read = ip->i_con_used;
}
}
}
void
ud_trunc_ext4096(struct ud_inode *ip, u_offset_t length)
{
ud_trunc_ext4(ip, length);
}
int32_t
ud_iflush(struct vfs *vfsp)
{
int32_t index, busy = 0;
union ihead *ih;
struct udf_vfs *udf_vfsp;
dev_t dev;
struct vnode *rvp, *vp;
struct ud_inode *ip, *next;
ud_printf("ud_iflush\n");
udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
rvp = udf_vfsp->udf_root;
dev = vfsp->vfs_dev;
mutex_enter(&ud_icache_lock);
for (index = 0; index < UD_HASH_SZ; index++) {
ih = &ud_ihead[index];
next = ih->ih_chain[0];
while (next != (struct ud_inode *)ih) {
ip = next;
next = ip->i_forw;
if (ip->i_dev != dev) {
continue;
}
vp = ITOV(ip);
if (vp == rvp) {
if (vp->v_count > 1) {
busy = -1;
}
continue;
}
if (ip->i_flag & IREF) {
busy = -1;
continue;
}
rw_enter(&ip->i_contents, RW_WRITER);
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
VN_HOLD(vp);
(void) ud_syncip(ip, B_INVAL, I_SYNC);
rw_exit(&ip->i_contents);
VN_RELE(vp);
}
}
mutex_exit(&ud_icache_lock);
return (busy);
}
int
ud_iaccess(struct ud_inode *ip, int32_t mode, struct cred *cr, int dolock)
{
int shift = 0;
int ret = 0;
if (dolock)
rw_enter(&ip->i_contents, RW_READER);
ASSERT(RW_LOCK_HELD(&ip->i_contents));
ud_printf("ud_iaccess\n");
if (mode & IWRITE) {
if (ip->i_udf->udf_flags & UDF_FL_RDONLY) {
if ((ip->i_type != VCHR) &&
(ip->i_type != VBLK) &&
(ip->i_type != VFIFO)) {
ret = EROFS;
goto out;
}
}
}
if (crgetuid(cr) != ip->i_uid) {
shift += 5;
if (!groupmember((uid_t)ip->i_gid, cr))
shift += 5;
}
ret = secpolicy_vnode_access2(cr, ITOV(ip), ip->i_uid,
UD2VA_PERM(ip->i_perm << shift), UD2VA_PERM(mode));
out:
if (dolock)
rw_exit(&ip->i_contents);
return (ret);
}
void
ud_imark(struct ud_inode *ip)
{
timestruc_t now;
gethrestime(&now);
ud_printf("ud_imark\n");
if (ip->i_flag & IACC) {
ip->i_atime.tv_sec = now.tv_sec;
ip->i_atime.tv_nsec = now.tv_nsec;
}
if (ip->i_flag & IUPD) {
ip->i_mtime.tv_sec = now.tv_sec;
ip->i_mtime.tv_nsec = now.tv_nsec;
ip->i_flag |= IMODTIME;
}
if (ip->i_flag & ICHG) {
ip->i_diroff = 0;
ip->i_ctime.tv_sec = now.tv_sec;
ip->i_ctime.tv_nsec = now.tv_nsec;
}
}
void
ud_itimes_nolock(struct ud_inode *ip)
{
ud_printf("ud_itimes_nolock\n");
if (ip->i_flag & (IUPD|IACC|ICHG)) {
if (ip->i_flag & ICHG) {
ip->i_flag |= IMOD;
} else {
ip->i_flag |= IMODACC;
}
ud_imark(ip);
ip->i_flag &= ~(IACC|IUPD|ICHG);
}
}
void
ud_delcache(struct ud_inode *ip)
{
ud_printf("ud_delcache\n");
mutex_enter(&ud_icache_lock);
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
mutex_exit(&ud_icache_lock);
}
void
ud_idrop(struct ud_inode *ip)
{
struct vnode *vp = ITOV(ip);
ASSERT(RW_WRITE_HELD(&ip->i_contents));
ud_printf("ud_idrop\n");
mutex_enter(&vp->v_lock);
VN_RELE_LOCKED(vp);
if (vp->v_count > 0) {
mutex_exit(&vp->v_lock);
return;
}
mutex_exit(&vp->v_lock);
mutex_enter(&ip->i_tlock);
mutex_enter(&udf_ifree_lock);
if (!vn_has_cached_data(vp) || ip->i_perm == 0) {
ud_add_to_free_list(ip, UD_BEGIN);
} else {
ud_add_to_free_list(ip, UD_END);
}
mutex_exit(&udf_ifree_lock);
ip->i_flag &= IMODTIME;
mutex_exit(&ip->i_tlock);
}
void
ud_add_to_free_list(struct ud_inode *ip, uint32_t at)
{
ASSERT(ip);
ASSERT(mutex_owned(&udf_ifree_lock));
#ifdef DEBUG
if (udf_ifreeh != NULL) {
struct ud_inode *iq;
iq = udf_ifreeh;
while (iq) {
if (iq == ip) {
cmn_err(CE_WARN, "Duplicate %p\n", (void *)ip);
}
iq = iq->i_freef;
}
}
#endif
ip->i_freef = NULL;
ip->i_freeb = NULL;
if (udf_ifreeh == NULL) {
udf_ifreeh = ip;
udf_ifreet = ip;
} else {
if (at == UD_BEGIN) {
ip->i_freef = udf_ifreeh;
udf_ifreeh->i_freeb = ip;
udf_ifreeh = ip;
} else {
ip->i_freeb = udf_ifreet;
udf_ifreet->i_freef = ip;
udf_ifreet = ip;
}
}
}
void
ud_remove_from_free_list(struct ud_inode *ip, uint32_t at)
{
ASSERT(ip);
ASSERT(mutex_owned(&udf_ifree_lock));
#ifdef DEBUG
{
struct ud_inode *iq;
uint32_t found = 0;
iq = udf_ifreeh;
while (iq) {
if (iq == ip) {
found++;
}
iq = iq->i_freef;
}
if (found != 1) {
cmn_err(CE_WARN, "ip %p is found %x times\n",
(void *)ip, found);
}
}
#endif
if ((ip->i_freef == NULL) && (ip->i_freeb == NULL)) {
if (ip != udf_ifreeh) {
return;
}
}
if ((at == UD_BEGIN) || (ip == udf_ifreeh)) {
udf_ifreeh = ip->i_freef;
if (ip->i_freef == NULL) {
udf_ifreet = NULL;
} else {
udf_ifreeh->i_freeb = NULL;
}
} else {
ip->i_freeb->i_freef = ip->i_freef;
if (ip->i_freef) {
ip->i_freef->i_freeb = ip->i_freeb;
} else {
udf_ifreet = ip->i_freeb;
}
}
ip->i_freef = NULL;
ip->i_freeb = NULL;
}
void
ud_init_inodes(void)
{
union ihead *ih = ud_ihead;
int index;
#ifndef __lint
_NOTE(NO_COMPETING_THREADS_NOW);
#endif
for (index = 0; index < UD_HASH_SZ; index++, ih++) {
ih->ih_head[0] = ih;
ih->ih_head[1] = ih;
}
mutex_init(&ud_icache_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&ud_nino_lock, NULL, MUTEX_DEFAULT, NULL);
udf_ifreeh = NULL;
udf_ifreet = NULL;
mutex_init(&udf_ifree_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&ud_sync_busy, NULL, MUTEX_DEFAULT, NULL);
udf_vfs_instances = NULL;
mutex_init(&udf_vfs_mutex, NULL, MUTEX_DEFAULT, NULL);
#ifndef __lint
_NOTE(COMPETING_THREADS_NOW);
#endif
}