[patch] Re: XFS, Quotas and Samba
Nathan Scott
nathans at sgi.com
Sun Sep 9 02:56:05 GMT 2001
hi,
On Thu, Sep 06, 2001 at 04:34:41PM +0200, Jan Kara wrote:
> Hello,
>
> Actually it depends whether the samba code was compiled with
> proper kernel headers. If so the Q_GETQUOTA is defined to be
> right value and so everything should work fine. Ok, to be more
> precise the utils probably won't compile in that case as struct dqblk
> is no more and mem_dqblk should be used instead... But anyway it shouldn't
> break silently.
Hmm ... I can't see any case where the new VFS quota code will
work (ie. Jan's patches/AC kernels/Redhat 7.1+) with the smbd
code, even if the kernel headers happened to correspond to the
running kernel. As I understand it, the new code returns a u64
byte count in one field (curspace) where before there was a u32
block count (curblocks). Is that correct? If so, smbd is in a
bit of strife here cos it peeks at that field in particular...
I took a stab at implementing the fix for this problem and for
XFS quota - the XFS code should be correct, the VFS quota code
(v1/v2 stuff) should be too, but I'm less certain on that - see
attached patch. The approach is basically to attempt the old
Linux quotactl for non-XFS filesystems - if that fails, try
the new version. And for XFS filesystems, always use the XFS
quotactl command, which is always the right thing to do.
Bret - could you let me know if this helps you?
cheers.
>
> > Just a quick followup - this is what I mentioned in my earlier
> > mail to you. I think your new VFS quota code (as in Alan Cox's
> > series of 2.4 kernels, for the Samba folk) will have exactly the
> > same problem as XFS. This "grep" would seem to confirm it - but
> > you'll know better than I here:
> >
> > 11:31 nathans at troppo ~/cvs/quota-tools 73> grep GETQUOTA dqblk*h
> > dqblk_rpc.h:#define Q_RPC_GETQUOTA 0x0300 /* get limits and usage */
> > dqblk_v1.h:#define Q_V1_GETQUOTA 0x300
> > dqblk_v2.h:#define Q_V2_GETQUOTA 0x0D00 /* Get limits and usage */
> > dqblk_xfs.h:#define Q_XFS_GETQUOTA Q_XGETQUOTA
> > 11:31 nathans at troppo ~/cvs/quota-tools 74>
> >
> > The samba code does a good old Q_GETQUOTA (ie. your V1 above).
> >
> > cheers.
> >
> >
> > On Thu, Sep 06, 2001 at 10:59:52AM +1100, Nathan Scott wrote:
> > > hi,
> > >
> > > On Wed, Sep 05, 2001 at 02:57:39PM +0100, Giddings, Bret wrote:
> > > > I am investigating whether I can replace my expensive Compaq Alphas file
> > > > servers with cheaper (and invariably faster given my budget) Intel based
> > > > ones. I have so far been pleased with the ease with which xfs has installed
> > > > and run on my hardware of choice. To make my life easier, I have picked up
> > > > the pre-built RedHat kernels with xfs support. Everything appears to be fine
> > > > except that when connecting to a share from Samba, the amount of free space
> > > > reported is the amount of free disk space left on the device rather than the
> > > > amount of free space in the users quota (this is on a disk mounted with
> > > > usrquota and a quota set for the users). The usual tools (edquota, setquota
> > > > work as expected).
> > > >
> > > > I have downloaded the source rpm for samba and it appears that RedHat build
> > > > their smbd to support quotas. I have also checked whether
> > > > /usr/include/sys/quota.h is modified by installing your updated quota rpm
> > > > (quota-3.01pre8) and it isn't. So, is there another reason why quotas don't
> > > > appear to work with xfs/samba?
> > >
> > > The samba code needs to be updated to support XFS quota under
> > > Linux. There was someone on the list a little while ago who
> > > was looking to add in the samba support for XFS quota, but I
> > > don't know how far they got.
> > >
> > > I know very little about samba unfortunately, but it should be
> > > quite simple to add this stuff for XFS - the disk_quotas()
> > > routine in samba-2.2.1a/source/smbd/quotas.c is all that needs
> > > to be changed, by the look of things.
> > >
> > > For XFS filesystems on Linux this needs to:
> > > - have logic to handle getmntent's of type "xfs" separately;
> > > - issue a quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), ..., &xdq) where
> > > xdq is of type "struct fs_disk_quota_t" from <linux/xqm.h>
> > > - set *bsize to 512 for XFS
> > > - refer to the code later in that same file for dealing with XFS
> > > on IRIX - basically, do exactly the same thing and it should
> > > just work.
> > > - to do it properly, the configure scripts will need to check
> > > for linux/xqm.h (or might be simpler to keep a local copy? -
> > > I dunno what sort of policy the samba folk have on this sort of
> > > thing, but this header isn't going to change and probably isn't
> > > going to appear in the libc headers for quite awhile...)
> > >
> > > cheers.
> > >
> > > --
> > > Nathan
> >
> > --
> > Nathan
> --
> Jan Kara <jack at suse.cz>
> SuSE Labs
--
Nathan
-------------- next part --------------
diff -Naur samba-2.2.1a/source/smbd/quotas.c samba-2.2.1a+ns/source/smbd/quotas.c
--- samba-2.2.1a/source/smbd/quotas.c Thu Jul 5 21:02:03 2001
+++ samba-2.2.1a+ns/source/smbd/quotas.c Sun Sep 9 09:29:58 2001
@@ -44,13 +44,10 @@
#ifdef LINUX
#include <sys/types.h>
-#include <asm/types.h>
+#include <linux/types.h>
#include <sys/quota.h>
-
#include <mntent.h>
-#include <linux/unistd.h>
-
-_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
+#include "quotas.h"
/****************************************************************************
try to get the disk space from disk quotas (LINUX version)
@@ -59,18 +56,20 @@
BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
int r;
- struct dqblk D;
+ v1_kern_dqblk_t D1;
+ v2_kern_dqblk_t D2;
+ fs_disk_quota_t DX;
SMB_STRUCT_STAT S;
FILE *fp;
struct mntent *mnt;
SMB_DEV_T devno;
int found;
uid_t euser_id;
+ static int version = 1; /* VFS quota version */
euser_id = geteuid();
-
+
/* find the block device file */
-
if ( sys_stat(path, &S) == -1 ) {
return(False) ;
}
@@ -91,47 +90,109 @@
endmntent(fp) ;
if (!found) {
- return(False);
- }
+ return(False);
+ }
save_re_uid();
set_effective_uid(0);
- r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
+ if (strcmp(mnt->mnt_type, "xfs") == 0)
+ r = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&DX);
+ else {
+ if (version == 1) {
+ r = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D1);
+ if (r == EINVAL)
+ version = 2;
+ }
+ if (version == 2)
+ r = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D2);
+ }
restore_re_uid();
- /* Use softlimit to determine disk space, except when it has been exceeded */
- *bsize = 1024;
if (r)
- {
- if (errno == EDQUOT)
- {
- *dfree =0;
- *dsize =D.dqb_curblocks;
- return (True);
- }
- else return(False);
+ return(False);
+
+ if (version == 1)
+ {
+ *bsize = 1024;
+ /* Use softlimit to determine disk space, except when its been exceeded */
+ if (
+ (D1.dqb_bsoftlimit && D1.dqb_curblocks>=D1.dqb_bsoftlimit) ||
+ (D1.dqb_bhardlimit && D1.dqb_curblocks>=D1.dqb_bhardlimit) ||
+ (D1.dqb_isoftlimit && D1.dqb_curinodes>=D1.dqb_isoftlimit) ||
+ (D1.dqb_ihardlimit && D1.dqb_curinodes>=D1.dqb_ihardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = D1.dqb_curblocks;
+ }
+ else if (D1.dqb_bsoftlimit==0 && D1.dqb_bhardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ if (D1.dqb_bsoftlimit == 0)
+ D1.dqb_bsoftlimit = D1.dqb_bhardlimit;
+ *dfree = D1.dqb_bsoftlimit - D1.dqb_curblocks;
+ *dsize = D1.dqb_bsoftlimit;
+ }
+ }
+ else if (version == 2)
+ {
+ *bsize = 1024;
+ D2.dqb_curspace >>= 10; /* bytes to Kbytes */
+ /* Use softlimit to determine disk space, except when its been exceeded */
+ if (
+ (D2.dqb_bsoftlimit && D2.dqb_curspace >=D2.dqb_bsoftlimit) ||
+ (D2.dqb_bhardlimit && D2.dqb_curspace >=D2.dqb_bhardlimit) ||
+ (D2.dqb_isoftlimit && D2.dqb_curinodes>=D2.dqb_isoftlimit) ||
+ (D2.dqb_ihardlimit && D2.dqb_curinodes>=D2.dqb_ihardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = D2.dqb_curspace;
+ }
+ else if (D2.dqb_bsoftlimit==0 && D2.dqb_bhardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ if (D2.dqb_bsoftlimit == 0)
+ D2.dqb_bsoftlimit = D2.dqb_bhardlimit;
+ *dfree = D2.dqb_bsoftlimit - D2.dqb_curspace;
+ *dsize = D2.dqb_bsoftlimit;
+ }
}
- /* Use softlimit to determine disk space, except when it has been exceeded */
- if (
- (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
- (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
- (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
- (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
- )
+ else if (strcmp(mnt->mnt_type, "xfs") == 0)
+ {
+ *bsize = 512;
+ /* Use softlimit to determine disk space, except when its been exceeded */
+ if (
+ (DX.d_blk_softlimit && DX.d_bcount>=DX.d_blk_softlimit) ||
+ (DX.d_blk_hardlimit && DX.d_bcount>=DX.d_blk_hardlimit) ||
+ (DX.d_ino_softlimit && DX.d_icount>=DX.d_ino_softlimit) ||
+ (DX.d_ino_hardlimit && DX.d_icount>=DX.d_ino_hardlimit)
+ )
{
*dfree = 0;
- *dsize = D.dqb_curblocks;
+ *dsize = DX.d_bcount;
}
- else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+ else if (DX.d_blk_softlimit==0 && DX.d_blk_hardlimit==0)
{
return(False);
}
- else {
- if (D.dqb_bsoftlimit == 0)
- D.dqb_bsoftlimit = D.dqb_bhardlimit;
- *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
- *dsize = D.dqb_bsoftlimit;
+ else
+ {
+ *dfree = (DX.d_blk_softlimit - DX.d_bcount);
+ *dsize = DX.d_blk_softlimit;
+ }
}
+ else
+ {
+ return(False);
+ }
+
return (True);
}
diff -Naur samba-2.2.1a/source/smbd/quotas.h samba-2.2.1a+ns/source/smbd/quotas.h
--- samba-2.2.1a/source/smbd/quotas.h Wed Dec 31 19:00:00 1969
+++ samba-2.2.1a+ns/source/smbd/quotas.h Sun Sep 9 09:29:58 2001
@@ -0,0 +1,58 @@
+#ifdef LINUX
+
+#define Q_V1_GETQUOTA 0x0300 /* VFS quota, version 1 */
+#define Q_V2_GETQUOTA 0x0D00 /* VFS quota, version 2 */
+#define Q_XGETQUOTA (('X'<<8)+0x3) /* XFS quota */
+
+/* struct for Q_V1_GETQUOTA */
+typedef struct v1_kern_dqblk {
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
+ u_int32_t dqb_curblocks; /* current block count */
+ u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */
+ u_int32_t dqb_isoftlimit; /* preferred inode limit */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ time_t dqb_btime; /* time limit for excessive disk use */
+ time_t dqb_itime; /* time limit for excessive files */
+} v1_kern_dqblk_t;
+
+/* struct for Q_V2_GETQUOTA */
+typedef u_int64_t qsize_t;
+typedef struct v2_kern_dqblk {
+ unsigned int dqb_ihardlimit;
+ unsigned int dqb_isoftlimit;
+ unsigned int dqb_curinodes;
+ unsigned int dqb_bhardlimit;
+ unsigned int dqb_bsoftlimit;
+ qsize_t dqb_curspace;
+ time_t dqb_btime;
+ time_t dqb_itime;
+} v2_kern_dqblk_t;
+
+/* struct for Q_XGETQUOTA */
+typedef struct fs_disk_quota {
+ __s8 d_version; /* version of this structure */
+ __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */
+ __u16 d_fieldmask; /* field specifier */
+ __u32 d_id; /* user, project, or group ID */
+ __u64 d_blk_hardlimit; /* absolute limit on disk blks */
+ __u64 d_blk_softlimit; /* preferred limit on disk blks */
+ __u64 d_ino_hardlimit; /* maximum # allocated inodes */
+ __u64 d_ino_softlimit; /* preferred inode limit */
+ __u64 d_bcount; /* # disk blocks owned by the user */
+ __u64 d_icount; /* # inodes owned by the user */
+ __s32 d_itimer; /* zero if within inode limits */
+ __s32 d_btimer; /* similar to above; for disk blocks */
+ __u16 d_iwarns; /* # warnings issued wrt num inodes */
+ __u16 d_bwarns; /* # warnings issued wrt disk blocks */
+ __s32 d_padding2; /* padding2 - for future use */
+ __u64 d_rtb_hardlimit; /* absolute limit on realtime blks */
+ __u64 d_rtb_softlimit; /* preferred limit on RT disk blks */
+ __u64 d_rtbcount; /* # realtime blocks owned */
+ __s32 d_rtbtimer; /* similar to above; for RT disk blks */
+ __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */
+ __s16 d_padding3; /* padding3 - for future use */
+ char d_padding4[8]; /* yet more padding */
+} fs_disk_quota_t;
+
+#endif /* LINUX */
More information about the samba-technical
mailing list