📄 dquot.c
字号:
schedule(); /* Try to wait for a moment... */ goto we_slept; } dquot = empty; dquot->dq_id = id; dquot->dq_type = type; dquot->dq_dev = sb->s_dev; dquot->dq_sb = sb; /* hash it first so it can be found */ insert_dquot_hash(dquot); read_dquot(dquot); } else { if (!dquot->dq_count++) remove_free_dquot(dquot); dqstats.cache_hits++; wait_on_dquot(dquot); if (empty) dqput(empty); } if (!dquot->dq_sb) { /* Has somebody invalidated entry under us? */ printk(KERN_ERR "VFS: dqget(): Quota invalidated in dqget()!\n"); dqput(dquot); return NODQUOT; } dquot->dq_referenced++; dqstats.lookups++; return dquot;}static struct dquot *dqduplicate(struct dquot *dquot){ if (dquot == NODQUOT) return NODQUOT; dquot->dq_count++; if (!dquot->dq_sb) { printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n"); dquot->dq_count--; return NODQUOT; } if (dquot->dq_flags & DQ_LOCKED) printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n"); dquot->dq_referenced++; dqstats.lookups++; return dquot;}static int dqinit_needed(struct inode *inode, short type){ int cnt; if (IS_NOQUOTA(inode)) return 0; if (type != -1) return inode->i_dquot[type] == NODQUOT; for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (inode->i_dquot[cnt] == NODQUOT) return 1; return 0;}static void add_dquot_ref(struct super_block *sb, short type){ struct list_head *p; if (!sb->dq_op) return; /* nothing to do */restart: file_list_lock(); for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { struct file *filp = list_entry(p, struct file, f_list); struct inode *inode = filp->f_dentry->d_inode; if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { struct vfsmount *mnt = mntget(filp->f_vfsmnt); struct dentry *dentry = dget(filp->f_dentry); file_list_unlock(); sb->dq_op->initialize(inode, type); dput(dentry); mntput(mnt); /* As we may have blocked we had better restart... */ goto restart; } } file_list_unlock();}/* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */static inline int dqput_blocks(struct dquot *dquot){ if (dquot->dq_count == 1) return 1; return 0;}/* Remove references to dquots from inode - add dquot to list for freeing if needed */int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *tofree_head){ struct dquot *dquot = inode->i_dquot[type]; int cnt; inode->i_dquot[type] = NODQUOT; /* any other quota in use? */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] != NODQUOT) goto put_it; } inode->i_flags &= ~S_QUOTA;put_it: if (dquot != NODQUOT) { if (dqput_blocks(dquot)) { if (dquot->dq_count != 1) printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count); list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */ return 1; } else dqput(dquot); /* We have guaranteed we won't block */ } return 0;}/* Free list of dquots - called from inode.c */void put_dquot_list(struct list_head *tofree_head){ struct list_head *act_head; struct dquot *dquot; lock_kernel(); act_head = tofree_head->next; /* So now we have dquots on the list... Just free them */ while (act_head != tofree_head) { dquot = list_entry(act_head, struct dquot, dq_free); act_head = act_head->next; list_del(&dquot->dq_free); /* Remove dquot from the list so we won't have problems... */ INIT_LIST_HEAD(&dquot->dq_free); dqput(dquot); } unlock_kernel();}static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number){ dquot->dq_curinodes += number; dquot->dq_flags |= DQ_MOD;}static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number){ dquot->dq_curblocks += number; dquot->dq_flags |= DQ_MOD;}static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number){ if (dquot->dq_curinodes > number) dquot->dq_curinodes -= number; else dquot->dq_curinodes = 0; if (dquot->dq_curinodes < dquot->dq_isoftlimit) dquot->dq_itime = (time_t) 0; dquot->dq_flags &= ~DQ_INODES; dquot->dq_flags |= DQ_MOD;}static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number){ if (dquot->dq_curblocks > number) dquot->dq_curblocks -= number; else dquot->dq_curblocks = 0; if (dquot->dq_curblocks < dquot->dq_bsoftlimit) dquot->dq_btime = (time_t) 0; dquot->dq_flags &= ~DQ_BLKS; dquot->dq_flags |= DQ_MOD;}static inline int need_print_warning(struct dquot *dquot, int flag){ switch (dquot->dq_type) { case USRQUOTA: return current->fsuid == dquot->dq_id && !(dquot->dq_flags & flag); case GRPQUOTA: return in_group_p(dquot->dq_id) && !(dquot->dq_flags & flag); } return 0;}/* Values of warnings */#define NOWARN 0#define IHARDWARN 1#define ISOFTLONGWARN 2#define ISOFTWARN 3#define BHARDWARN 4#define BSOFTLONGWARN 5#define BSOFTWARN 6/* Print warning to user which exceeded quota */static void print_warning(struct dquot *dquot, const char warntype){ char *msg = NULL; int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS : ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES : 0); if (!need_print_warning(dquot, flag)) return; dquot->dq_flags |= flag; tty_write_message(current->tty, (char *)bdevname(dquot->dq_sb->s_dev)); if (warntype == ISOFTWARN || warntype == BSOFTWARN) tty_write_message(current->tty, ": warning, "); else tty_write_message(current->tty, ": write failed, "); tty_write_message(current->tty, quotatypes[dquot->dq_type]); switch (warntype) { case IHARDWARN: msg = " file limit reached.\n"; break; case ISOFTLONGWARN: msg = " file quota exceeded too long.\n"; break; case ISOFTWARN: msg = " file quota exceeded.\n"; break; case BHARDWARN: msg = " block limit reached.\n"; break; case BSOFTLONGWARN: msg = " block quota exceeded too long.\n"; break; case BSOFTWARN: msg = " block quota exceeded.\n"; break; } tty_write_message(current->tty, msg);}static inline void flush_warnings(struct dquot **dquots, char *warntype){ int i; for (i = 0; i < MAXQUOTAS; i++) if (dquots[i] != NODQUOT && warntype[i] != NOWARN) print_warning(dquots[i], warntype[i]);}static inline char ignore_hardlimit(struct dquot *dquot){ return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type];}static int check_idq(struct dquot *dquot, ulong inodes, char *warntype){ *warntype = NOWARN; if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; if (dquot->dq_ihardlimit && (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !ignore_hardlimit(dquot)) { *warntype = IHARDWARN; return NO_QUOTA; } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !ignore_hardlimit(dquot)) { *warntype = ISOFTLONGWARN; return NO_QUOTA; } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && dquot->dq_itime == 0) { *warntype = ISOFTWARN; dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type]; } return QUOTA_OK;}static int check_bdq(struct dquot *dquot, ulong blocks, char prealloc, char *warntype){ *warntype = 0; if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; if (dquot->dq_bhardlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = BHARDWARN; return NO_QUOTA; } if (dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = BSOFTLONGWARN; return NO_QUOTA; } if (dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && dquot->dq_btime == 0) { if (!prealloc) { *warntype = BSOFTWARN; dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type]; } else /* * We don't allow preallocation to exceed softlimit so exceeding will * be always printed */ return NO_QUOTA; } return QUOTA_OK;}/* * Initialize a dquot-struct with new quota info. This is used by the * system call interface functions. */ static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk){ struct dquot *dquot; int error = -EFAULT; struct dqblk dq_dqblk; if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk))) return error; if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) { /* We can't block while changing quota structure... */ if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) { dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit; dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit; dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit; dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit; } if ((flags & SET_QUOTA) || (flags & SET_USE)) { if (dquot->dq_isoftlimit && dquot->dq_curinodes < dquot->dq_isoftlimit && dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit) dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type]; dquot->dq_curinodes = dq_dqblk.dqb_curinodes; if (dquot->dq_curinodes < dquot->dq_isoftlimit) dquot->dq_flags &= ~DQ_INODES; if (dquot->dq_bsoftlimit && dquot->dq_curblocks < dquot->dq_bsoftlimit && dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit) dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type]; dquot->dq_curblocks = dq_dqblk.dqb_curblocks; if (dquot->dq_curblocks < dquot->dq_bsoftlimit) dquot->dq_flags &= ~DQ_BLKS; } if (id == 0) { dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime; dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime; } if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 && dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0) dquot->dq_flags |= DQ_FAKE; else dquot->dq_flags &= ~DQ_FAKE; dquot->dq_flags |= DQ_MOD; dqput(dquot); } return 0;}static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk){ struct dquot *dquot; struct dqblk data; int error = -ESRCH; if (!sb || !sb_has_quota_enabled(sb, type)) goto out; dquot = dqget(sb, id, type); if (dquot == NODQUOT) goto out; memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk)); /* We copy data to preserve them from changing */ dqput(dquot); error = -EFAULT; if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk))) error = 0;out: return error;}static int get_stats(caddr_t addr){ int error = -EFAULT; struct dqstats stats; dqstats.allocated_dquots = nr_dquots; dqstats.free_dquots = nr_free_dquots; /* make a copy, in case we page-fault in user space */ memcpy(&stats, &dqstats, sizeof(struct dqstats)); if (!copy_to_user(addr, &stats, sizeof(struct dqstats))) error = 0; return error;}static int quota_root_squash(struct super_block *sb, short type, int *addr){ int new_value, error; if (!sb) return(-ENODEV); error = -EFAULT; if (!copy_from_user(&new_value, addr, sizeof(int))) { sb_dqopt(sb)->rsquash[type] = new_value; error = 0; } return error;}#if 0 /* We are not going to support filesystems without i_blocks... *//* * This is a simple algorithm that calculates the size of a file in blocks. * This is only used on filesystems that do not have an i_blocks count. */static u_long isize_to_blocks(loff_t isize, size_t blksize_bits){ u_long blocks; u_long indirect; if (!blksize_bits) blksize_bits = BLOCK_SIZE_BITS; blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0); if (blocks > 10) { indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */ if (blocks > (10 + 256)) { indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */ if (blocks > (10 + 256 + (256 << 8))) indirect++; /* triple indirect blocks */ } blocks += indirect; } return blocks;}#endif/* * Externally referenced functions through dquot_operations in inode. * * Note: this is a blocking operation. */void dquot_initialize(struct inode *inode, short type){ struct dquot *dquot[MAXQUOTAS]; unsigned int id = 0; short cnt; if (IS_NOQUOTA(inode)) return; /* Build list of quotas to initialize... We can block here */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { dquot[cnt] = NODQUOT; if (type != -1 && cnt != type) continue; if (!sb_has_quota_enabled(inode->i_sb, cnt)) continue; if (inode->i_dquot[cnt] == NODQUOT) { switch (cnt) { case USRQUOTA: id = inode->i_uid; break; case GRPQUOTA: id = inode->i_gid; break; } dquot[cnt] = dqget(inode->i_sb, id, cnt); } } /* NOBLOCK START: Here we shouldn't block */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (dquot[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt) || inode->i_dquot[cnt] != NODQUOT) continue; inode->i_dquot[cnt] = dquot[cnt]; dquot[cnt] = NODQUOT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -