#include <bits/stdc++.h>
//#include <boost/algorithm/string.hpp>
//#include <string>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define vii vector<pair<int,int> >
#define vi vector<int>
#define pb(x) push_back(x)
#define pbm(x,y) push_back({x,y})
#define ff first
#define ss second
#define vll vector<pair<ll,ll> >
#define vl vector<ll>
const double pi = 3.14159265358979323846;
#define int ll
ll mod = 1000000007;
//#define int ll
/*
vector < int> g[200001];
bool vis[200001]={0};


ll kmp(string x)
{
    ll n= x.length();
    //cout<<x<<endl;
    vector<ll> lcp(x.length(), 0);
    for(ll i=1;i<n;i++)
    {
        ll j=lcp[i-1];
        while(j>0 && x[j]!=x[i])
            j=lcp[j-1];
        if(x[i]==x[j])
            j++;
        lcp[i]=j;
    }
    return lcp[n-1];
}
ll dp[10000000]={0};
int power(ll x,ll y)
{
    ll res = 1;

    while (y > 0) {

        if (y & 1)
            res = (res * x)%mod;


        y = y >> 1;
        x = (x * x)%mod;
    }
    return res%mod;
}
bool fun(ll a)
{
    for (ll i=2;i<=sqrt(a);i++)
    {
        if (a%i==0)
            return false;
    }
    return true;
}
int lps(string s)
{
   int n = s.size();
   int i, j, cl;
   int l[n][n];
   for (i = 0; i < n; i++)
      l[i][i] = 1;
    for (cl=2; cl<=n; cl++)
    {
        for (i=0; i<n-cl+1; i++)
        {
            j = i+cl-1;
            if (s[i] == s[j] && cl == 2)
               l[i][j] = 2;
            else if (s[i] == s[j])
               l[i][j] = l[i+1][j-1] + 2;
            else
               l[i][j] = max(l[i][j-1], l[i+1][j]);
        }
    }

    return l[0][n-1];
}
bool sortinrev(const pair<int,int> &a,
               const pair<int,int> &b)
{
       return (a.first > b.first );
}

int l=0;
int a[100001];ll n,m,ans=0;
bool vis[1000];
vector <int> adj[10000];
bool vis[100001]={0};
vector<int>v[100001];
void dfs(int s)
{
    vis[s] = true;
    for(int i = 0;i < adj[s].size();++i)
    {
        if(vis[adj[s][i]] == false)
            dfs(adj[s][i]);
    }
}
int knapSack(int W,int n)
{
if (n == 0 || W == 0)
    return 0;
if (p[n-1] > W)
    return knapSack(W, n-1);
else return max( v[n-1] + knapSack(W-p[n-1], n-1),  knapSack(W, n-1) );
}*/

/*template <typename T, int MaxLen, typename Container=std::deque<T>>
class FixedQueue : public std::queue<T, Container>
{
    public:
    void push(const T& value)
    {
        if (this->size() == MaxLen)
        {
           this->c.pop_front();
        }
        std::queue<T, Container>::push(value);
    }
};
int gcd(int a, int b)
{
    if (b == 0)
        return a;
    return gcd(b, a % b);
}
ll findlcm(int arr[], int n)
{
    ll ans = arr[0];
    for (int i = 1; i < n; i++)
        ans = (((arr[i] * ans)) /
                (gcd(arr[i], ans)));
    return ans;
}
ll gcd(ll a, ll b)
{
    if (b == 0)
        return a;
    return gcd(b, a % b);
}
ll power(ll x,ll y)
{
    ll res = 1;

    while (y > 0) {

        if (y & 1)
            res = (res * x)%mod;


        y = y >> 1;
        x = (x * x)%mod;
    }
    return res%mod;
}
ll cubic_root(ll x){
    ll l = 1 , r=1000001;
    while(l<=r){
        ll m = (l+r)/2;
        if((m*m*m) == x)
            return m;
        else if(m*m*m > x)
            r = m-1;
        else
            l = m + 1;
    }
    return -1;
}
ll combi[1001][1001];
ll expo[1001];
bool flag;

void f() {
    if(flag) return;
    flag = 1;
    for(int n = 0; n < 1001; n += 1) {
        for(int k = 0; k <= n; k += 1) {
            if (k == 0 or k == n) {
                combi[n][k] = 1;
            }
            else {
                combi[n][k] = (combi[n-1][k] + combi[n-1][k-1]) % mod;
            }
        }
    }
    expo[0] = 1;
    for (int i = 1; i < 1001; i += 1) {
        expo[i] = (2 * expo[i-1]) % mod;
    }
}
ll step(ll cur,ll x)
{
    if(cur-x > 0)
        return cur - x;
    else
        return cur + x;
}

int power(ll x,ll y)
{
    ll res = 1;

    while (y > 0) {

        if (y & 1)
            res = (res * x)%mod;


        y = y >> 1;
        x = (x * x)%mod;
    }
    return res%mod;
}
int fun(ll n)
{
    if (n % 2 == 0)
        return n/2;

    for (int i = 3; i * i <= n; i += 2) {
        if (n % i == 0)
            return n/i;
    }

    return 1;
}
bool comp(const pll &a,
               const pll &b)
{
    if(a.first==b.first)return a.second<b.second;
       return (a.first < b.first );
}
int gcd(int x, int y) { return __gcd(x, y); }
long long lcm(int x, int y) { return x * 1ll * y / gcd(x, y); }



int mul(int x, int y)
{
    return (x * 1ll * y) % mod;
}
ll power(ll x,ll y)
{
    ll res = 1;

    while (y > 0) {

        if (y & 1)
            res = (res * x)% mod;


        y = y >> 1;
        x = (x * x)% mod;
    }
    return res%mod;
}
int inv(int x)
{
    return power(x,mod- 2);
}

int divide(int x, int y)
{
    return mul(x, inv(y));
}

int fact[200001];

void precalc()
{
    fact[0] = 1;
    for(int i = 1; i < 200001; i++)
        fact[i] = mul(fact[i - 1], i);
}

int C(int n, int k)
{
    return divide(fact[n], mul(fact[k], fact[n - k]));
}
int n,m,cn=0;
const int dx[]={1,1,-1,-1};
const int dy[]={1,0,0,1};
//int vis[51];;
int c=0;
vector <int> adj[51];
void dfs(int s)
{
    vis[s]=1;c++;
    for(int i=0;i<adj[s].size();i++)
    {
        if(vis[adj[s][i]]==0)
            dfs(adj[s][i]);
    }
}
ll kmp(string x)
{
    ll n= x.length();
    //cout<<x<<endl;
    vector<ll> lcp(x.length(), 0);
    for(ll i=1;i<n;i++)
    {
        ll j=lcp[i-1];
        while(j>0 && x[j]!=x[i])
            j=lcp[j-1];
        if(x[i]==x[j])
            j++;
        lcp[i]=j;
    }
    return lcp[n-1];
}
vl ppp;
void simpleSieve(int limit, vector<int> &prime)
{

    bool mark[limit+1];
    memset(mark, true, sizeof(mark));

    for (int p=2; p*p<limit; p++)
    {
        // If p is not changed, then it is a prime
        if (mark[p] == true)
        {
            // Update all multiples of p
            for (int i=p*2; i<limit; i+=p)
                mark[i] = false;
        }
    }

    // Print all prime numbers and store them in prime
    for (int p=2; p<limit; p++)
    {
        if (mark[p] == true)
        {
            prime.push_back(p);
            ppp.pb(p);
           // cout << p << " ";
        }
    }
}

void segmentedSieve(int n)
{

    int limit = floor(sqrt(n))+1;
    vector<int> prime;
    simpleSieve(limit, prime);


    int low = limit;
    int high = 2*limit;


    while (low < n)
    {
        if (high >= n)
           high = n;


        bool mark[limit+1];
        memset(mark, true, sizeof(mark));


        for (int i = 0; i < prime.size(); i++)
        {

            int loLim = floor(low/prime[i]) * prime[i];
            if (loLim < low)
                loLim += prime[i];
            for (int j=loLim; j<high; j+=prime[i])
                mark[j-low] = false;
        }
        for (int i = low; i<high; i++)
            if (mark[i - low] == true)
                ppp.pb(i);//cout << i << " ";
        low = low + limit;
        high = high + limit;
    }
}
bool iscycleodd(int n,int s)
{
    int colorArr[n+1];
    for (int i = 0; i <=n; ++i)
        colorArr[i] = -1;
    colorArr[s] = 1;
    queue <int> q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int v = 0; v < adj[u].size(); ++v)
        {
            if (colorArr[adj[u][v]] == -1)
            {

                colorArr[adj[u][v]] = 1 - colorArr[u];
                q.push(adj[u][v]);
            }

            else if (colorArr[adj[u][v]] == colorArr[u])
                return true;
        }
    }

    return false;
}
void bfs(int s)
{
    queue <int> q;
    q.push(s);
    ls[ s ] = 1 ;
    vis[ s ] = true;
    while(!q.empty())
    {
        int p = q.front();
        q.pop();
        for(int i = 0;i < adj[ p ].size() ; i++)
        {
            if(vis[ adj[ p ][ i ] ] == false)
            {
                ls[ adj[ p ][ i ] ] = ls[ p ]+1;
                q.push(adj[ p ][ i ]);
                vis[ adj[ p ][ i ] ] = true;
            }
        }
    }
}

vector <int> adj[200001];
vector<int>c(200001,0);
int vis[200001];
int cc,x=0;
void dfs(int s)
{
    vis[s]=1;cc=0;
    for(int i=0;i<adj[s].size();i++)
    {
        if(vis[adj[s][i]]==0 && c[adj[s][i]]==0)
            cc++;
    }
    if(cc==adj[s].size())
    {
        for(int i=0;i<adj[s].size();i++)
            vis[adj[s][i]]=1;
        cout<<s<<" ";
        x++;
    }
}
string s1="",s2="",s3="";
int n,k;
int fun(string s,int p)
{
    int x=k,c=0;
    for(int i=0;i<k;i++)
    {
        if(s[i+p]!=s1[i])c++;
    }
    //cout<<c<<" ";
    x=min(x,c);
    c=0;
    for(int i=0;i<k;i++)
    {
        if(s[i+p]!=s2[i])c++;
    }
    //cout<<c<<" ";
    x=min(x,c);
    c=0;
    for(int i=0;i<k;i++)
    {
        if(s[i+p]!=s3[i])c++;
    }
    x=min(x,c);
    //cout<<c<<" "<<endl;
    //cout<<x<<endl;
    return x;
}*/
//int dp[131072][131072][26]={0};
vector<vector<int> > v;
int dp[100001];
int dfs(int i)
{
    if(dp[i]!=1)return dp[i];
    else
    {
        for(int j=0;j<v[i].size();j++)
            dp[i]=max(dp[i],1+dfs(v[i][j]));
        return dp[i];
    }
}

int32_t main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int t=1;
    //cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        v.resize(n+1);
        for(int i=0;i<=100001;i++)dp[i]=1;
        for(int i=0;i<m;i++)
        {
            int x,y;
            cin>>x>>y;
            v[x].push_back(y);
        }
        int ans=-1;
        for(int i=0;i<n;i++)
        {
            ans=max(ans,dfs(i+1));
        }
        cout<<ans-1;

    }
    return 0;
}




Measured memory_bytes: 11500